{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Title: #Stone Game"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Difficulty: #Medium"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Category Title: #Algorithms"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tag Slug: #array #math #dynamic-programming #game-theory"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Name Translated: #数组 #数学 #动态规划 #博弈"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Solution Name: stoneGame"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Translated Title: #石子游戏"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Translated Content:\n",
    "<p>Alice 和 Bob 用几堆石子在做游戏。一共有偶数堆石子，<strong>排成一行</strong>；每堆都有 <strong>正</strong> 整数颗石子，数目为 <code>piles[i]</code>&nbsp;。</p>\n",
    "\n",
    "<p>游戏以谁手中的石子最多来决出胜负。石子的 <strong>总数</strong> 是 <strong>奇数</strong> ，所以没有平局。</p>\n",
    "\n",
    "<p>Alice 和 Bob 轮流进行，<strong>Alice 先开始</strong> 。 每回合，玩家从行的 <strong>开始</strong> 或 <strong>结束</strong> 处取走整堆石头。 这种情况一直持续到没有更多的石子堆为止，此时手中 <strong>石子最多</strong> 的玩家 <strong>获胜</strong> 。</p>\n",
    "\n",
    "<p>假设 Alice 和 Bob 都发挥出最佳水平，当 Alice 赢得比赛时返回&nbsp;<code>true</code>&nbsp;，当 Bob 赢得比赛时返回&nbsp;<code>false</code>&nbsp;。</p>\n",
    "\n",
    "<p>&nbsp;</p>\n",
    "\n",
    "<p><strong>示例 1：</strong></p>\n",
    "\n",
    "<pre>\n",
    "<strong>输入：</strong>piles = [5,3,4,5]\n",
    "<strong>输出：</strong>true\n",
    "<strong>解释：</strong>\n",
    "Alice 先开始，只能拿前 5 颗或后 5 颗石子 。\n",
    "假设他取了前 5 颗，这一行就变成了 [3,4,5] 。\n",
    "如果 Bob 拿走前 3 颗，那么剩下的是 [4,5]，Alice 拿走后 5 颗赢得 10 分。\n",
    "如果 Bob 拿走后 5 颗，那么剩下的是 [3,4]，Alice 拿走后 4 颗赢得 9 分。\n",
    "这表明，取前 5 颗石子对 Alice 来说是一个胜利的举动，所以返回 true 。\n",
    "</pre>\n",
    "\n",
    "<p><strong>示例 2：</strong></p>\n",
    "\n",
    "<pre>\n",
    "<strong>输入：</strong>piles = [3,7,2,3]\n",
    "<strong>输出：</strong>true\n",
    "</pre>\n",
    "\n",
    "<p>&nbsp;</p>\n",
    "\n",
    "<p><strong>提示：</strong></p>\n",
    "\n",
    "<ul>\n",
    "\t<li><code>2 &lt;= piles.length &lt;= 500</code></li>\n",
    "\t<li><code>piles.length</code> 是 <strong>偶数</strong></li>\n",
    "\t<li><code>1 &lt;= piles[i] &lt;= 500</code></li>\n",
    "\t<li><code>sum(piles[i])</code>&nbsp;是 <strong>奇数</strong></li>\n",
    "</ul>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Description: [stone-game](https://leetcode.cn/problems/stone-game/description/)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Solutions: [stone-game](https://leetcode.cn/problems/stone-game/solutions/)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "test_cases = ['[5,3,4,5]', '[3,7,2,3]']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "\n",
    "        s, n = 0, len(piles)\n",
    "\n",
    "        f = [[0] * (n + 1) for _ in range(n)]\n",
    "\n",
    "        for i in range(n - 1, -1, -1):\n",
    "\n",
    "            s += piles[i]\n",
    "\n",
    "            for m in range(1, i // 2 + 2):\n",
    "\n",
    "                if i + m * 2 >= n:\n",
    "\n",
    "                    f[i][m] = s\n",
    "\n",
    "                else:\n",
    "\n",
    "                    f[i][m] = s - min(f[i + x][max(m, x)] for x in range(1, m * 2 + 1))\n",
    "\n",
    "        return f[0][1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n, memo = len(piles), dict()\n",
    "\n",
    "        # 定义s[i]为第i堆石子到最后一堆石子的总石子数\n",
    "        s = [0] * (n+1)\n",
    "        for i in range(n - 1, -1, -1):\n",
    "            s[i] = s[i + 1] + piles[i]\n",
    "\n",
    "        def dfs(i, M):\n",
    "            \"\"\"定义从第i堆石子开始取，最多取M堆可以得到的最优值\"\"\"\n",
    "\n",
    "            if (i, M) in memo:\n",
    "                return memo[(i, M)]\n",
    "\n",
    "            if i >= n:\n",
    "                return 0\n",
    "            if i + M * 2 >= n:\n",
    "                return s[i]\n",
    "\n",
    "            best = 0\n",
    "            for x in range(1, M * 2 + 1):\n",
    "                best = max(best, s[i] - dfs(i + x, max(x, M)))\n",
    "\n",
    "            memo[(i, M)] = best\n",
    "            return best\n",
    "\n",
    "        return dfs(0, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "        if n == 1:\n",
    "            return piles[0]\n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "        total = 0\n",
    "        for i in range(n - 1,-1,-1):\n",
    "            total += piles[i]\n",
    "            for m in range(1,n):\n",
    "                if i + 2 * m >= n:\n",
    "                    dp[i][m] = total\n",
    "                else:\n",
    "                    for x in range(1, 2 * m + 1):\n",
    "                        dp[i][m] = max(dp[i][m], total - dp[i + x][max(m,x)])\n",
    "\n",
    "        return dp[0][1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        s, n = 0, len(piles)\n",
    "        f = [[0] * (n + 1) for _ in range(n)]\n",
    "        for i in range(n - 1, -1, -1):\n",
    "            s += piles[i]\n",
    "            for m in range(1, i // 2 + 2):\n",
    "                if i + m * 2 >= n:\n",
    "                    f[i][m] = s\n",
    "                else:\n",
    "                    f[i][m] = s - min(f[i + x][max(m, x)] for x in range(1, m * 2 + 1))\n",
    "        return f[0][1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        s = [0]*len(piles)\n",
    "        s[len(piles)-1] = piles[len(piles)-1]\n",
    "        Dict = {}\n",
    "        for i in range(len(piles) - 2, -1, -1):\n",
    "            s[i] = piles[i] + s[i+1]\n",
    "        def dfs(i: int, M: int) -> int:\n",
    "            if i + 2*M >= len(piles):\n",
    "                return s[i]\n",
    "            if (i,M) in Dict:\n",
    "                return Dict[(i,M)]\n",
    "            else:\n",
    "                Dict[(i,M)] = s[i] - min(dfs(i+x,max(M,x))for x in range(1,2*M + 1))\n",
    "                return Dict[(i,M)] \n",
    "        return dfs(0,1)\n",
    "        \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, ps: List[int]) -> int:\n",
    "        # n = len(s)\n",
    "        # for i in range(n - 2, -1, -1):\n",
    "        #     s[i] += s[i + 1] #后缀和\n",
    "\n",
    "        # @cache\n",
    "        # def dfs(i: int, m:int) ->int:\n",
    "        #     if i + m * 2 >= n: #能全拿\n",
    "        #         return s[i]\n",
    "        #     return s[i] - min(dfs(i + x, max(m, x)) for x in range(1, m * 2 + 1))\n",
    "        # return dfs(0, 1)\n",
    "\n",
    "\n",
    "        # 迭代\n",
    "        s, n = 0, len(ps)\n",
    "        f = [[0] * (n +1) for _ in range(n)]\n",
    "        for i in range(n - 1, -1, -1):\n",
    "            s += ps[i]\n",
    "            for m in range(1, i // 2 +2):\n",
    "                if i + m * 2 >= n:\n",
    "                    f[i][m] = s\n",
    "                else:\n",
    "                    f[i][m] = s - min(f[i + x][max(m, x)] for x in range(1, m * 2 + 1))\n",
    "\n",
    "        return f[0][1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        s, n = 0, len(piles)\n",
    "        f = [[0] * (n + 1) for _ in range(n)]\n",
    "        for i in range(n - 1, -1, -1):\n",
    "            s += piles[i]\n",
    "            for m in range(1, i // 2 + 2):\n",
    "                if i + m * 2 >= n:\n",
    "                    f[i][m] = s\n",
    "                else:\n",
    "                    f[i][m] = s - min(f[i + x][max(m, x)] for x in range(1, m * 2 + 1))\n",
    "        return f[0][1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        s, n = 0, len(piles)\n",
    "        f = [[0] * (n + 1) for _ in range(n)]\n",
    "        for i in range(n - 1, -1, -1):\n",
    "            s += piles[i]\n",
    "            for m in range(1, i // 2 + 2):\n",
    "                if i + m * 2 >= n:\n",
    "                    f[i][m] = s\n",
    "                else:\n",
    "                    f[i][m] = s - min(f[i + x][max(m, x)] for x in range(1, m * 2 + 1))\n",
    "\n",
    "        return f[0][1]\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        s, n = 0, len(piles)\n",
    "        f = [[0] * (n + 1) for _ in range(n)]\n",
    "        for i in range(n - 1, -1, -1):\n",
    "            s += piles[i]\n",
    "            for m in range(1, i // 2 + 2):\n",
    "                if i + m * 2 >= n:\n",
    "                    f[i][m] = s\n",
    "                else:\n",
    "                    f[i][m] = s - min(f[i + x][max(m, x)] for x in range(1, m * 2 + 1))\n",
    "        return f[0][1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "        suffix = [0 for _ in range(n + 1)]\n",
    "        dp = [[0 for _ in range(n + 1)] for _ in range(51)]\n",
    "        for i in reversed(range(n)):\n",
    "            dp[50][i] = piles[i] + dp[50][i + 1]\n",
    "            \n",
    "        \n",
    "        for i in reversed(range(1, 50)):\n",
    "            for j in reversed(range(n)):\n",
    "                mi = int(1e9)\n",
    "                for k in range(1, min(n - j, 2 * i) + 1):\n",
    "                    k = min(k, 50)\n",
    "                    mi = min(dp[max(i, k)][j + k], mi)\n",
    "                dp[i][j] = dp[50][j] - mi\n",
    "        \n",
    "        # print(dp)\n",
    "\n",
    "        return dp[1][0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        s,n = 0,len(piles)\n",
    "        f = [[0] * (n + 1) for _ in range(n)]\n",
    "        for i in range(n - 1,-1,-1):\n",
    "            s += piles[i]\n",
    "            for m in range(1, i // 2 + 2):\n",
    "                if i + m * 2 >= n:\n",
    "                    f[i][m] = s\n",
    "                else:\n",
    "                    f[i][m] = s - min(f[i + x][max(m,x)] for x in range(1,2*m+1))        \n",
    "        return f[0][1]\n",
    "        # @cache\n",
    "        # def dfs(i,m) -> int:\n",
    "        #     if i + m * 2 >= n:\n",
    "        #         return piles[i]\n",
    "        #     mn = inf\n",
    "        #     for j in range(1,2 * m + 1):\n",
    "        #         mn = min(mn,dfs(i + j,max(m,j)))\n",
    "        #     return piles[i] - mn\n",
    "        # return dfs(0,1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "        suffix = [0 for _ in range(n + 1)]\n",
    "        dp = [[0 for _ in range(n + 1)] for _ in range(51)]\n",
    "        for i in reversed(range(n)):\n",
    "            suffix[i] = piles[i] + suffix[i + 1]\n",
    "            dp[50][i] = suffix[i]\n",
    "        \n",
    "        for i in reversed(range(1, 50)):\n",
    "            for j in reversed(range(n)):\n",
    "                mi = int(1e9)\n",
    "                for k in range(1, min(n - j, 2 * i) + 1):\n",
    "                    k = min(k, 50)\n",
    "                    mi = min(dp[max(i, k)][j + k], mi)\n",
    "                dp[i][j] = suffix[j] - mi\n",
    "        \n",
    "        # print(dp)\n",
    "\n",
    "        return dp[1][0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n=len(piles)\n",
    "        res=[[0]*(n+1) for _ in range(n+1)]\n",
    "        for i in range(n-1,-1,-1):\n",
    "            for m in range(1,n+1):\n",
    "                if i+2*m>=n:\n",
    "                    res[i][m]=sum(piles[i:n])\n",
    "                else:\n",
    "                    for choice in range(1,2*m+1):\n",
    "                        res[i][m]=max(res[i][m],sum(piles[i:n])-res[i+choice][max(m,choice)])\n",
    "        return res[0][1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        if len(piles) <= 2: return sum(piles)\n",
    "\n",
    "        n = len(piles)\n",
    "        dp = [[0]*n for _ in range(n)]\n",
    "        tailsum = 0\n",
    "        for i in range(n-1, -1, -1):\n",
    "            tailsum += piles[i]\n",
    "            for m in range(n-1, 0, -1):\n",
    "                if 2*m >= n-i:\n",
    "                    dp[i][m] = tailsum\n",
    "                else:\n",
    "                    for x in range(1, 2*m+1):\n",
    "                        dp[i][m] = max(dp[i][m], tailsum-dp[i+x][max(m,x)])\n",
    "        return dp[0][1]\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        # dp[i][m], max alice can win with piles[i:] and m\n",
    "        # dp[i][m] = max(dp[i])\n",
    "        # first calculate the prefix sum\n",
    "        sfx_sum = 0\n",
    "        dp = [[0] * (len(piles) + 1) for _ in range(len(piles))]\n",
    "        for i in range(len(piles) - 1, -1, -1):\n",
    "            sfx_sum += piles[i]\n",
    "            for m in range(1, len(piles) + 1):\n",
    "                for x in range(1, 2 * m + 1):\n",
    "                    if i + x >= len(piles):\n",
    "                        dp[i][m] = max(dp[i][m], sfx_sum)\n",
    "                    else:\n",
    "                        dp[i][m] = max(dp[i][m], sfx_sum - dp[i + x][max(m, x)])\n",
    "        return dp[0][1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        # dp[i][m]: optimal value to collect piles[i:][m] with m\n",
    "        n = len(piles)\n",
    "        dp = [[0] * (n + 1) for _ in range(n)]\n",
    "        suffix_sum = 0\n",
    "        for i in range(n - 1, -1, -1):\n",
    "            suffix_sum += piles[i]\n",
    "            for m in range(1, n + 1):\n",
    "                for x in range(1, 2 * m + 1):\n",
    "                    if i + x >= n:\n",
    "                        # player can take all the stones\n",
    "                        dp[i][m] = max(dp[i][m], suffix_sum)\n",
    "                    else:\n",
    "                        dp[i][m] = max(dp[i][m], suffix_sum - dp[i + x][max(x, m)])\n",
    "        return dp[0][1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\r\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\r\n",
    "        n = len(piles)\r\n",
    "        prices = [i for i in piles]\r\n",
    "        for i in range(n - 2, -1, -1):\r\n",
    "            prices[i] += prices[i + 1]\r\n",
    "\r\n",
    "        dp = [[0] * (n + 1) for _ in range(n)]\r\n",
    "\r\n",
    "        for i in range(n - 1, -1, -1):\r\n",
    "            for j in range(1, n + 1):\r\n",
    "                if i + 2 * j >= n:\r\n",
    "                    dp[i][j] = prices[i]\r\n",
    "                else:\r\n",
    "                    for k in range(1, 2 * j + 1):\r\n",
    "                        dp[i][j] = max(dp[i][j], prices[i] - dp[i + k][max(j, k)])\r\n",
    "        return dp[0][1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "\n",
    "        # dp[i][m]: i:len, m\n",
    "        n_len = len(piles)\n",
    "\n",
    "        if n_len <= 2:\n",
    "            return sum(piles)\n",
    "\n",
    "        dp = [[0 for i in range(n_len)] for j in range(n_len)]\n",
    "        \n",
    "        for i in range(n_len-1, -1, -1):\n",
    "            for m in range(n_len-1, 0, -1):\n",
    "                if n_len-i <= 2 * m:\n",
    "                    dp[i][m] = sum(piles[i:n_len])\n",
    "                else:\n",
    "                    for j in range(i, i + 2 * m):\n",
    "                        new_m = max(m, j-i+1)\n",
    "                        dp[i][m] = max(dp[i][m], sum(piles[i:n_len]) - dp[j+1][new_m])\n",
    "        \n",
    "        # print(dp)\n",
    "        return dp[0][1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "        pre_fix = [0]\n",
    "        for x in piles:\n",
    "            pre_fix.append(pre_fix[-1] + x)\n",
    "        \n",
    "        M = 1\n",
    "        f = [[0] * (n + 1) for _ in range(n + 1)]\n",
    "\n",
    "        for i in range(n-1, -1, -1):\n",
    "            for j in range(n, 0, -1):\n",
    "                t = pre_fix[-1] - pre_fix[i]\n",
    "                if i + 2 * j >= n:\n",
    "                    f[i][j] = t\n",
    "                else:\n",
    "                    for k in range(1, 2 * j + 1):\n",
    "                        f[i][j] = max(f[i][j], t - f[i+k][min(max(j, k), n)])\n",
    "        \n",
    "        return f[0][1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, s: List[int]) -> int:\n",
    "        n = len(s)\n",
    "        for i in range(n - 2, -1, -1):\n",
    "            s[i] += s[i + 1]  # 计算后缀和\n",
    "\n",
    "        # i 表示当前从第几堆开始拿\n",
    "        @cache\n",
    "        def dfs(i: int, M: int) -> int:\n",
    "            if i + M * 2 >= n:  # 能全拿\n",
    "                return s[i]\n",
    "            bob = float('inf')\n",
    "            for x in range(1, M * 2 + 1):\n",
    "                # 如果拿了某几堆石子后，BOB得到的石子数最少，Alice能得到的石子数就是最多的\n",
    "                bob = min(bob, dfs(i + x, max(M, x)))\n",
    "            return s[i] - bob\n",
    "\n",
    "        return dfs(0, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, s: List[int]) -> int:\n",
    "        n = len(s)\n",
    "        for i in range(n - 2, -1, -1):\n",
    "            s[i] += s[i + 1]  # 后缀和\n",
    "\n",
    "        @cache\n",
    "        def dfs(i: int, m: int) -> int:\n",
    "            if i + m * 2 >= n:  # 能全拿\n",
    "                return s[i]\n",
    "            return s[i] - min(dfs(i + x, max(m, x)) for x in range(1, m * 2 + 1))\n",
    "        return dfs(0, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, s: List[int]) -> int:\n",
    "        n=len(s)\n",
    "        for i in range(n-2,-1,-1):\n",
    "            s[i]+=s[i+1]\n",
    "        \n",
    "        @cache\n",
    "        def dfs(i: int,m: int)->int:\n",
    "            if i+m*2>=n:\n",
    "                return s[i]\n",
    "            return s[i]-min(dfs(i+x,max(m,x)) for x in range(1,m*2+1))\n",
    "        return dfs(0,1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        # f[n][m] 在piles[n:] 中，M为m时，先取的人能够获得的最大石头数量\n",
    "        f = [[0] * (len(piles) + 1) for _ in range(len(piles))]\n",
    "        for n in range(len(piles) - 1, -1, -1):\n",
    "            for m in range(1, len(piles) + 1):\n",
    "                if 2 * m >= len(piles) - n:\n",
    "                    f[n][m] = sum(piles[n:])\n",
    "                else:\n",
    "                    for x in range(1, 2 * m + 1):\n",
    "                        f[n][m] = max(f[n][m], sum(piles[n:]) - f[n + x][max(m, x)])\n",
    "        return f[0][1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        if len(piles) == 1:\n",
    "            return piles[0]\n",
    "        import sys\n",
    "        M = len(piles)\n",
    "        prefix = [0] * (M + 1)\n",
    "        for i in range(M):\n",
    "            prefix[i + 1] = prefix[i] + piles[i]\n",
    "        first = [[0] * M for _ in range(M)]\n",
    "        second = [[0] * M for _ in range(M)]\n",
    "        for i in range(M - 1, -1, -1):\n",
    "            for j in range(M - 1, -1, -1):\n",
    "                if M - i <= 2 * j:\n",
    "                    first[i][j] = prefix[M] - prefix[i]  # sum(piles[i:])\n",
    "                else:\n",
    "                    second[i][j] = sys.maxsize\n",
    "                    for k in range(1, 2 * j + 1):\n",
    "                        # sum(piles[i:i + k]) = prefix[i + k] - prefix[i]\n",
    "                        first[i][j] = max(first[i][j], prefix[i + k] - prefix[i] + second[i + k][max(k, j)])\n",
    "                        second[i][j] = min(second[i][j], first[i + k][max(k, j)])\n",
    "        return first[0][1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, s: List[int]) -> int:\n",
    "        n = len(s)\n",
    "        for i in range(n - 2, -1, -1):\n",
    "            s[i] += s[i + 1]  # 后缀和\n",
    "\n",
    "        # 对于每个节点，由于剩余的石子总数是固定的\n",
    "        # 如果拿了某几堆石子后，对手能得到的石子数最少，那么自己能得到的石子数就是最多的\n",
    "        @lru_cache(None)\n",
    "        def dfs(i: int, m: int) -> int:\n",
    "            if i + m * 2 >= n:  # 能全拿\n",
    "                return s[i]\n",
    "            return s[i] - min(dfs(i + x, max(m, x)) for x in range(1, m * 2 + 1))\n",
    "        return dfs(0, 1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "# 尚未优化，会超时\n",
    "class Solution:\n",
    "    def stoneGameII(self, s: List[int]) -> int:\n",
    "        n = len(s)\n",
    "        for i in range(n - 2, -1, -1):\n",
    "            s[i] += s[i + 1]  # 后缀和\n",
    "\n",
    "        @cache \n",
    "        def dfs(i: int, m: int) -> int:\n",
    "            if i + m * 2 >= n:  # 能全拿\n",
    "                return s[i]\n",
    "            res = inf \n",
    "            for x in range(1, m*2+1):\n",
    "                res = min(res, dfs(i+x, max(m, x)))\n",
    "            return s[i] - res \n",
    "        return dfs(0, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\r\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\r\n",
    "        n = len(piles)\r\n",
    "        for i in range(n - 2, -1, -1):\r\n",
    "            piles[i] += piles[i + 1]\r\n",
    "\r\n",
    "        @lru_cache(None)\r\n",
    "        def dfs(i, m):\r\n",
    "            if i + 2 * m >= n: \r\n",
    "                return piles[i]\r\n",
    "            return piles[i] - min(dfs(i + x, max(m, x)) for x in range(1, 2 * m + 1))\r\n",
    "        return dfs(0, 1)\r\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\r\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\r\n",
    "        n = len(piles)\r\n",
    "        for i in range(n - 2, -1, -1):\r\n",
    "            piles[i] += piles[i + 1]\r\n",
    "\r\n",
    "        @lru_cache(None)\r\n",
    "        def dfs(i, m):\r\n",
    "            if i + 2 * m >= n: \r\n",
    "                return piles[i]\r\n",
    "            return piles[i] - min(dfs(i + x, max(m, x)) for x in range(1, 2 * m + 1))\r\n",
    "        return dfs(0, 1)\r\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import sys\n",
    "class Solution:\n",
    "    def init(self, piles):\n",
    "        self.n = len(piles)\n",
    "        self.memo = {}\n",
    "        self.psum = self.calPrefixSum(piles)\n",
    "        print(self.psum)\n",
    "\n",
    "    def calPrefixSum(self, piles):\n",
    "        n = len(piles)\n",
    "        psum = [0] * n\n",
    "        psum[0] = piles[0]\n",
    "        for i in range(1, n):\n",
    "            psum[i] = psum[i-1] + piles[i]\n",
    "        return psum\n",
    "\n",
    "    def gameRoundAttacker(self, k, m):\n",
    "        if k >= self.n:\n",
    "            return 0\n",
    "        stamp = '%d:%d:0' % (k,m)\n",
    "        if stamp in self.memo:\n",
    "            return self.memo[stamp]\n",
    "\n",
    "        maxTaken = min(self.n-k, 2*m)\n",
    "        maxStones = 0\n",
    "        for taken in range(1, maxTaken+1):\n",
    "            takenStones = (self.psum[k+taken-1] - self.psum[k-1]) if k > 0 else self.psum[k+taken-1]\n",
    "            scores = takenStones + self.gameRoundDefender(k + taken, max(m, taken))\n",
    "\n",
    "            maxStones = max(maxStones, scores)\n",
    "            #if k == 0:\n",
    "            #    print(\"[debug, attacker, k=0] taken:[%d] taken[%d] final[%d]\" % (taken, takenStones,scores))\n",
    "        \n",
    "        self.memo[stamp] = maxStones\n",
    "        return maxStones\n",
    "\n",
    "    def gameRoundDefender(self, k, m):\n",
    "        if k >= self.n:\n",
    "            return 0\n",
    "        stamp = '%d:%d:1' % (k,m)\n",
    "        if stamp in self.memo:\n",
    "            return self.memo[stamp]\n",
    "        \n",
    "        maxTaken = min(self.n-k, 2*m)\n",
    "        minStones = sys.maxsize\n",
    "        for taken in range(1, maxTaken+1):\n",
    "            lostStones = self.gameRoundAttacker(k+taken, max(m,taken))\n",
    "            minStones = min(minStones, lostStones)\n",
    "        self.memo[stamp] = minStones\n",
    "        return minStones\n",
    "\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        self.init(piles)\n",
    "        points = self.gameRoundAttacker(0, 1)\n",
    "        #print(self.memo)\n",
    "        return points"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "        for i in range(n - 2, -1, -1):\n",
    "            piles[i] += piles[i + 1]  # 后缀和\n",
    "\n",
    "        @cache\n",
    "        def dfs(i: int, m: int) -> int:\n",
    "            if i + m * 2 >= n:  # 能全拿\n",
    "                return piles[i]\n",
    "            return piles[i] - min(dfs(i + x, max(m, x)) for x in range(1, m * 2 + 1))\n",
    "        return dfs(0, 1)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "        acc = list(accumulate(piles,initial=0))\n",
    "\n",
    "        @cache\n",
    "        def f(i,m):\n",
    "            if i+m >=n: return acc[-1]-acc[i]\n",
    "            res = float('-inf')\n",
    "            for j in range(i,min(i+2*m,n)):\n",
    "                res = max(res,acc[j+1]-acc[i]-f(j+1,max(m,j+1-i)))\n",
    "            return res\n",
    "        \n",
    "        ans = f(0,1)\n",
    "        return ans+(sum(piles)-ans)//2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, s: List[int]) -> int:\n",
    "        n = len(s)\n",
    "        for i in range(n - 2, -1, -1):\n",
    "            s[i] += s[i + 1]  # 后缀和\n",
    "\n",
    "        @cache\n",
    "        def dfs(i: int, m: int) -> int:\n",
    "            if i + m * 2 >= n:  # 能全拿\n",
    "                return s[i]\n",
    "            return s[i] - min(dfs(i + x, max(m, x)) for x in range(1, m * 2 + 1))\n",
    "        return dfs(0, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "\n",
    "        # 后缀和计算剩余价值\n",
    "        for i in range(n-2, -1, -1):\n",
    "            piles[i] += piles[i+1]\n",
    "\n",
    "        @cache\n",
    "        def dfs(i, m):\n",
    "            if i + 2 * m >= n:\n",
    "                return piles[i]\n",
    "            return piles[i] - min(dfs(i+j, max(m, j)) for j in range(1, 2*m+1))\n",
    "\n",
    "        return dfs(0, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        prevsum = list(accumulate(piles))\n",
    "        def sumij(i, j):\n",
    "            if i == 0:\n",
    "                return prevsum[j]\n",
    "            return prevsum[j] - prevsum[i-1]\n",
    "        n = len(piles)\n",
    "        @cache\n",
    "        def f(M, i):\n",
    "            if 2 * M >= n - i:\n",
    "                return sumij(i, n-1)\n",
    "            maxv = 0\n",
    "            for X in range(1, 2 * M + 1):\n",
    "                a = sumij(i, i+X-1)\n",
    "                a += sumij(i+X, n-1) - f(max(M, X), i+X)\n",
    "                if a > maxv:\n",
    "                    maxv = a\n",
    "            return maxv\n",
    "\n",
    "        return f(1, 0)\n",
    "            \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        # dp[i][j]: 剩余[i:len-1]堆时，M=j的情况下，先取的人能获得的最多石子数量\n",
    "        n = len(piles)\n",
    "        dp = [[0]*(n+1) for _ in range(n)]\n",
    "        # 初始化\n",
    "\n",
    "        # 递推\n",
    "        for i in range(n-1,-1,-1):\n",
    "            for M in range(1,n+1):\n",
    "                if i+2*M>=n: \n",
    "                    dp[i][M] = sum(piles[i:])\n",
    "                else:\n",
    "                    for x in range(1, 2*M+1):\n",
    "                        dp[i][M] = max(dp[i][M], sum(piles[i:])-dp[i+x][max(x,M)])\n",
    "        print(dp)\n",
    "        return dp[0][1]\n",
    "        \n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "# +- 型\n",
    "\n",
    "# 亚历克斯和李继续他们的石子游戏。许多堆石子 排成一行，每堆都有正整数颗石子 piles[i]。游戏以谁手中的石子最多来决出胜负。\n",
    "\n",
    "# 亚历克斯和李轮流进行，亚历克斯先开始。最初，M = 1。\n",
    "\n",
    "# 在每个玩家的回合中，该玩家可以拿走剩下的 前 X 堆的所有石子，其中 1 <= X <= 2M。然后，令 M = max(M, X)。\n",
    "\n",
    "# 游戏一直持续到所有石子都被拿走。\n",
    "\n",
    "# 假设亚历克斯和李都发挥出最佳水平，返回亚历克斯可以得到的最大数量的石头\n",
    "\n",
    "# [2,7,9,4,4]\n",
    "# x - y = a\n",
    "# x + y = sum\n",
    "# x = (a + sum) / 2\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        @lru_cache(None)\n",
    "        def dp(M, i):\n",
    "            if i >= len(piles):\n",
    "                return 0\n",
    "            ans, acc = float(\"-inf\"), 0\n",
    "            for j in range(2 * M):\n",
    "                if i + j < len(piles):\n",
    "                    acc += piles[i + j]\n",
    "                else:\n",
    "                    break\n",
    "                ans = max(ans, acc - dp(max(M, j + 1), i + j + 1))\n",
    "            return ans\n",
    "\n",
    "        return (dp(1, 0) + sum(piles)) // 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        \n",
    "        # 从下标n开始取，可取[1,2*m]堆时，先手能的的最大分\n",
    "        @cache\n",
    "        def dfs(n,m):\n",
    "            if n == len(piles) :\n",
    "                return 0\n",
    "          \n",
    "            total = sum(piles[n:])\n",
    "            score = 0\n",
    "            for x in range(1,2*m+1):\n",
    "                # 取得堆数x超过了剩下的堆数\n",
    "                if x>len(piles)-n:\n",
    "                    break\n",
    "                score = max(score,total-dfs(n+x, max(x,m)) )\n",
    "    \n",
    "            return score\n",
    "        \n",
    "        return dfs(0, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        \n",
    "        prefixSum = [0]\n",
    "        for a in piles:\n",
    "            prefixSum.append(prefixSum[-1] + a)\n",
    "        \n",
    "        @lru_cache(None)\n",
    "        def dp(i, m):\n",
    "            if i == len(piles):\n",
    "                return 0\n",
    "            mx = -inf\n",
    "            for x in range(1, 2 * m + 1):                \n",
    "                if i+x > len(piles):\n",
    "                    break\n",
    "                mx = max(mx, prefixSum[i + x] - prefixSum[i] - dp(i + x, max(m, x)))\n",
    "            return mx\n",
    "            \n",
    "        return (prefixSum[-1]+dp(0, 1)) // 2\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "        @lru_cache(None)\n",
    "        def stone(n, m):\n",
    "            if n == 0:\n",
    "                return 0\n",
    "            elif n == 1:\n",
    "                return piles[-1]\n",
    "            else:\n",
    "                x = [sum(piles[-n:]) - stone(n - i, max(m, i)) for i in range(1, min(2 * m, n) + 1)]\n",
    "                return max(x)\n",
    "        return stone(n, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        @cache\n",
    "        def dfs(i, m):\n",
    "            if m * 2 >= n - i:\n",
    "                return s[n] - s[i]\n",
    "            return max(s[n] - s[i] - dfs(i + x, max(m, x)) \n",
    "            for x in range(1, m << 1 | 1))\n",
    "\n",
    "        n = len(piles)\n",
    "        s = list(accumulate(piles, initial=0))\n",
    "        return dfs(0, 1)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "presum = [0] * 101\r\n",
    "class Solution:\r\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\r\n",
    "        n = len(piles)\r\n",
    "        for i in range(n): presum[i + 1] = presum[i] + piles[i]\r\n",
    "\r\n",
    "        @cache\r\n",
    "        def min_max(i: int, M: int) -> int:\r\n",
    "            if i == n: return 0\r\n",
    "            return max(presum[i + x] - presum[i] + (0 if i + x == n else (min(min_max(i + x + y, min(max(M, x, y), (n - i - x - y + 1) >> 1)) for y in range(1, min(max(M, x) << 1, n - i - x) + 1)))) for x in range(1, min(M << 1, n - i) + 1))\r\n",
    "\r\n",
    "        return min_max(0, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        t=len(piles)\n",
    "        ww={}\n",
    "        for i in range(t-2,-1,-1):\n",
    "            piles[i]+=piles[i+1]\n",
    "        def dfs(x,m):\n",
    "            if (x,m) in ww:\n",
    "                return ww[(x,m)]\n",
    "            ans=0\n",
    "            if t-x<=2*m:\n",
    "                return piles[x]\n",
    "            for i in range(1,1+2*m):\n",
    "                ans=max(ans,piles[x]-dfs(x+i,max(m,i)))\n",
    "            ww[(x,m)]=ans\n",
    "            return ans\n",
    "        return dfs(0,1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "        add_sum = [0]*(n+1)\n",
    "        for i in range(1,n+1):\n",
    "            add_sum[i] = add_sum[i-1] + piles[i-1]\n",
    "        self.rec = [[0]*n for _ in range(n)]\n",
    "\n",
    "        def dfs(idx, m):\n",
    "            # idx开始的数组 目前M=m值\n",
    "            # return 先手， 后手分别取得的最大数\n",
    "            total = add_sum[n] - add_sum[idx]\n",
    "            remain = n - idx + 1\n",
    "            if 2*m>=remain:\n",
    "                return total, 0\n",
    "            if not self.rec[idx][m] == 0:\n",
    "                return self.rec[idx][m], total - self.rec[idx][m]\n",
    "            max_res = 0\n",
    "            for i in range(1,2*m+1):\n",
    "                if idx+i>n:\n",
    "                    break\n",
    "                first = add_sum[idx+i] - add_sum[idx]\n",
    "                r1, r2 = dfs(idx+i, max(i,m))\n",
    "                max_res = max(first + r2, max_res)\n",
    "            self.rec[idx][m] = max_res\n",
    "            return max_res, total - max_res\n",
    "        \n",
    "        first, secend = dfs(0, 1)\n",
    "        return first"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        #官方不好理解\n",
    "        # predixsum=[0]\n",
    "        # for pile in piles:\n",
    "        #     predixsum.append(predixsum[-1]+pile)\n",
    "        # #dfs(i,m) 表示前 i 堆石头已经被取走，当前的M=m的情况下，接下去取石头的玩家可以比另一方多取的石头数\n",
    "        # #取走前i堆，剩下的第i+1堆对应的索引就是i\n",
    "        # def dp(i,m):\n",
    "        #     if i==len(piles):\n",
    "        #         return 0\n",
    "        #     mx=-inf\n",
    "        #     for x in range(1,2*m+1):\n",
    "        #         if i+x>len(piles):\n",
    "        #             break\n",
    "        #         mx=max(mx,predixsum[i+x]-predixsum[i]-dp(i+x,max(x,m)))\n",
    "        #     return mx\n",
    "        # return int((predixsum[-1]+dp(0,1))/2)\n",
    "\n",
    "        #解释版本\n",
    "        n=len(piles)\n",
    "        suffixsum=[0]*(n+1)\n",
    "        for i in range(n-1,-1,-1):\n",
    "            suffixsum[i]=piles[i]+suffixsum[i+1]\n",
    "\n",
    "        cache=[[0]*(n+1) for _ in range(n)]\n",
    "        def dfs(i,m):\n",
    "            if i>=n:\n",
    "                return 0\n",
    "            if (i+2*m-1)>=(n-1):\n",
    "                return suffixsum[i]\n",
    "            if cache[i][m]==0:\n",
    "                minstones=inf\n",
    "                for x in range(1,2*m+1):\n",
    "                    minstones=min(minstones,dfs(i+x,max(x,m)))\n",
    "                cache[i][m]=suffixsum[i]-minstones\n",
    "            return cache[i][m]\n",
    "        return dfs(0,1)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        pq=sum(piles)\n",
    "        m=1\n",
    "        t=len(piles)\n",
    "        ww={}\n",
    "        zz=[]\n",
    "        ff=piles[:]\n",
    "        for i in range(t-2,-1,-1):\n",
    "            ff[i]+=ff[i+1]\n",
    "        def dfs(x,m):\n",
    "            if (x,m) in ww:\n",
    "                return ww[(x,m)]\n",
    "            ans=0\n",
    "            if t-x<=2*m:\n",
    "                return ff[x]\n",
    "            for i in range(1,1+2*m):\n",
    "                ans=max(ans,ff[x]-dfs(x+i,max(m,i)))\n",
    "            ww[(x,m)]=ans\n",
    "            return ans\n",
    "        return (dfs(0,1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "presum = [0] * 101\r\n",
    "class Solution:\r\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\r\n",
    "        n = len(piles)\r\n",
    "        for i in range(n): presum[i + 1] = presum[i] + piles[i]\r\n",
    "\r\n",
    "        @cache\r\n",
    "        def min_max(i: int, M: int) -> int:\r\n",
    "            if i == n: return 0\r\n",
    "            return max(presum[i + x] - presum[i] + (0 if i + x == n else (min(min_max(i + x + y, min(max(M, x, y), (n - i - x - y + 1) >> 1)) for y in range(1, min(max(M, x) << 1, n - i - x) + 1)))) for x in range(min(M << 1, n - i), 0, -1))\r\n",
    "\r\n",
    "        return min_max(0, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        #官方不好理解\n",
    "        # predixsum=[0]\n",
    "        # for pile in piles:\n",
    "        #     predixsum.append(predixsum[-1]+pile)\n",
    "        # #dfs(i,m) 表示前 i 堆石头已经被取走，当前的M=m的情况下，接下去取石头的玩家可以比另一方多取的石头数\n",
    "        # #取走前i堆，剩下的第i+1堆对应的索引就是i\n",
    "        # def dp(i,m):\n",
    "        #     if i==len(piles):\n",
    "        #         return 0\n",
    "        #     mx=-inf\n",
    "        #     for x in range(1,2*m+1):\n",
    "        #         if i+x>len(piles):\n",
    "        #             break\n",
    "        #         mx=max(mx,predixsum[i+x]-predixsum[i]-dp(i+x,max(x,m)))\n",
    "        #     return mx\n",
    "        # return int((predixsum[-1]+dp(0,1))/2)\n",
    "\n",
    "        #解释版本,相对好理解\n",
    "        #dfs(i,m) 表示前 i 堆石头已经被取走（取走前i堆，剩下的第i+1堆对应的索引就是i），当前的M=m的情况下，接下去取石头的玩家获得最大收益\n",
    "        #当前双方已经取走了前i堆石子，还剩下[i, len - 1]堆石子\n",
    "        # 那么我们希望知道在当前的M，我们从这[i, len - 1]堆石子能得到的最大收益，即获取到的最多石子是有多少。\n",
    "        #1.首先明确一个计算公式，我们从位置i取走X堆石子，取走的是[i, i + X - 1]范围的石子，还剩下[i + X , len - 1]堆石子。\n",
    "        #2.如果我们基于当前的M值可以把[i, len - 1]全部取完，那么最大值就是全部取完的值。也就是说i + X - 1 >= len - 1的时候取走了所有的石子。只要最大的X = 2*m满足这个条件即可，即i + 2 * m >= len；\n",
    "        #3.否则我们只能去枚举X ∈ {1， 2*m]的每一种情况，去看我们取走的是[i, i + X - 1]范围的石子之后对手的最大收益是多少。【当前剩余的石子范围变成了[i + X , len - 1]，，M变成max(X, m)，那么对手的最大收益就是dfs(i + X, max(X, m))】，我们要选择是这些情况中对手最大收益最小的那个X，我们的收益 = 当前剩下石子总和sum[i, len - 1] - 对手最小的最大收益min{dfs(i + X, max(X, m))}\n",
    "        #我们可以看到不论是两种情况的哪一种，我们都需要当前剩下石子总和sum[i, len - 1]的值，因为我们使用后缀和的方式先把每个位置i的总和sum[i, len - 1]统计下来。 同时递归的过程，很有可能会对同一个i和m的值dfs(i, m)重复调用，因此我们可以使用一个数组cache[i][m]进行记忆，减少时间开销。\n",
    "        n=len(piles)\n",
    "        suffixsum=[0]*(n+1)\n",
    "        for i in range(n-1,-1,-1):\n",
    "            suffixsum[i]=piles[i]+suffixsum[i+1]\n",
    "\n",
    "        cache=[[0]*(2*n) for _ in range(n)]\n",
    "        def dfs(i,m):\n",
    "            if i>=n:\n",
    "                return 0\n",
    "            if (i+2*m-1)>=(n-1):\n",
    "                return suffixsum[i]\n",
    "            if cache[i][m]==0:\n",
    "                minstones=inf\n",
    "                for x in range(1,2*m+1):\n",
    "                    minstones=min(minstones,dfs(i+x,max(x,m)))\n",
    "                cache[i][m]=suffixsum[i]-minstones\n",
    "            return cache[i][m]\n",
    "        return dfs(0,1)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles) -> int:\n",
    "        n = len(piles)\n",
    "        memo = {}        \n",
    "        # postsum[i] 表示第 i 堆石子到最后一堆石子的总石子数 (剩余石子)\n",
    "        postsum = [0] * (n + 1) # eg [26, 24, 17, 8, 4, 0]\n",
    "        for i in range(n - 1, -1, -1):\n",
    "            postsum[i] = postsum[i + 1] + piles[i]\n",
    "            \n",
    "        # dfs(i, M) 表示从第 i 堆石子开始取，最多能取 M 堆石子所能得到的最优值\n",
    "        def dfs(i, M):\n",
    "            if (i, M) in memo:\n",
    "                return memo[(i, M)]\n",
    "            if i >= n:\n",
    "                return 0\n",
    "            # 如果剩余堆数小于等于 2M， 那么可以全拿走 (base case)\n",
    "            if n - i <= M *2:\n",
    "                return postsum[i]\n",
    "            # 枚举拿 x 堆的最优值\n",
    "            res = float('-inf')\n",
    "            # restraint 2: pick from [1, 2M]\n",
    "            for x in range(1, M * 2 + 1):\n",
    "                # 剩余石子减去对方最优策略\n",
    "                res = max(res, postsum[i] - dfs(i + x, max(x, M))) # update new M\n",
    " \n",
    "            memo[(i, M)] = res\n",
    "            return res\n",
    "        \n",
    "        return dfs(0, 1) # 1st restraint: init M=1\n",
    "\n",
    "\n",
    "\n",
    "\"\"\"\n",
    "本题难点在于理解两者都发挥“最佳水平”，“最佳水平”在于，每当轮到自己拿石子的时候，要在后继的所有状态中，选择对自己最有利的，那么也就是要遍历后继的所有状态，并选择一个最优解。我们设 dfs(i, M) 表示，当从第 i 堆石子开始拿，允许拿 M <= x <= 2 * M 时，在剩余石子中所能拿到的最大值，那么我们最终要返回的结果就是 dfs(0, 1)。搜索状态时，我们要遵循以下几个原则：\n",
    "\n",
    "如果 i >= n，那么说明石子都已经拿完，直接返回 0；\n",
    "如果 i + M * 2 >= n，那么说明可以把剩余石子一起拿到，就可以直接返回剩余石子的数目 sum(piles[i:])；\n",
    "如果不属于以上两种情况，那么我们需要遍历 1 <= x <= 2 * M，求剩余的最小 dfs(i + x, max(x, M))，也就是自己拿多少的时候，对手拿的石子最少（由于剩余石子数固定，那么最小化对手石子数，就是最大化自己的石子数）。\n",
    "为了防止重复搜索，可以采用记忆化的方法。为了快速求剩余石子数目，可以提前处理后缀和。\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles) -> int:\n",
    "        n = len(piles)\n",
    "        memo = {}        \n",
    "   \n",
    "        # dfs(i, M) 表示从第 i 堆石子开始取，最多能取 M 堆石子所能得到的最优值\n",
    "        def dfs(i, M):\n",
    "            if (i, M) in memo:\n",
    "                return memo[(i, M)]\n",
    "            if i >= n:\n",
    "                return 0\n",
    "            # 如果剩余堆数小于等于 2M， 那么可以全拿走\n",
    "            if  n - i <= M *2:\n",
    "                return sum(piles[i: ])\n",
    "            # 枚举拿 x 堆的最优值\n",
    "            res = 0\n",
    "            # restraint 2: pick from [1, 2M]\n",
    "             # explore each x\n",
    "            for x in range(1, M * 2 + 1):\n",
    "                # 剩余石子减去对方最优策略. diff is the current palyers score, keep max\n",
    "                res = max(res, \n",
    "                           sum(piles[i: ]) - dfs(i + x,  max(x, M))) # Then, we set M = max(M, X)\n",
    " \n",
    "            memo[(i, M)] = res\n",
    "            return res\n",
    "        \n",
    "        return dfs(0, 1) # 1st restraint: init M=1\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "SUPER GOOD ***：https://leetcode-cn.com/problems/stone-game-ii/solution/ji-yi-hua-sou-suo-python3-by-smoon1989/\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "        memo = {}\n",
    "\n",
    "        s = [0] * (n + 1)\n",
    "\n",
    "        # 这个倒叙的过程，就是还剩下多少石子\n",
    "        for i in range(n - 1, -1, -1):\n",
    "            s[i] = s[i + 1] + piles[i]\n",
    "        \n",
    "        def dfs(i, M):\n",
    "            if (i , M) in memo:\n",
    "                return memo[(i, M)]\n",
    "            if i >= n:\n",
    "                return 0\n",
    "            if i + 2*M >= n:\n",
    "                return s[i] #就是可以返回剩下所有的石子数量\n",
    "            max_ = 0\n",
    "            for j in range(1, 2*M + 1):\n",
    "                max_ = max(max_, s[i] - dfs(i + j, max(j, M)))\n",
    "            memo[(i, M)] = max_\n",
    "            return max_\n",
    "\n",
    "        return dfs(0, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        # 数据规模与记忆化\n",
    "        n, memo = len(piles), dict()\n",
    "        \n",
    "        # s[i] 表示第 i 堆石子到最后一堆石子的总石子数\n",
    "        s = [0] * (n + 1)\n",
    "        for i in range(n - 1, -1, -1):\n",
    "            s[i] = s[i + 1] + piles[i]\n",
    "            \n",
    "        # dfs(i, M) 表示从第 i 堆石子开始取，最多能取 M 堆石子所能得到的最优值\n",
    "        def dfs(i, M):\n",
    "            # 如果已经搜索过，直接返回\n",
    "            if (i, M) in memo:\n",
    "                return memo[(i, M)]\n",
    "            # 溢出拿不到任何石子\n",
    "            if i >= n:\n",
    "                return 0\n",
    "            # 如果剩余堆数小于等于 2M， 那么可以全拿走\n",
    "            if i + M * 2 >= n:\n",
    "                return s[i]\n",
    "            # 枚举拿 x 堆的最优值\n",
    "            best = 0\n",
    "            for x in range(1, M * 2 + 1):\n",
    "                # 剩余石子减去对方最优策略\n",
    "                best = max(best, s[i] - dfs(i + x, max(x, M)))\n",
    "            # 记忆化\n",
    "            memo[(i, M)] = best\n",
    "            return best\n",
    "        \n",
    "        return dfs(0, 1)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        # 数据规模与记忆化\n",
    "        n, memo = len(piles), dict()\n",
    "        \n",
    "        # s[i] 表示第 i 堆石子到最后一堆石子的总石子数\n",
    "        s = [0] * (n + 1)\n",
    "        for i in range(n - 1, -1, -1):\n",
    "            s[i] = s[i + 1] + piles[i]\n",
    "            \n",
    "        # dfs(i, M) 表示从第 i 堆石子开始取，最多能取 M 堆石子所能得到的最优值\n",
    "        def dfs(i, M):\n",
    "            # 如果已经搜索过，直接返回\n",
    "            if (i, M) in memo:\n",
    "                return memo[(i, M)]\n",
    "            # 溢出拿不到任何石子\n",
    "            if i >= n:\n",
    "                return 0\n",
    "            # 如果剩余堆数小于等于 2M， 那么可以全拿走\n",
    "            if i + M * 2 >= n:\n",
    "                return s[i]\n",
    "            # 枚举拿 x 堆的最优值\n",
    "            best = 0\n",
    "            for x in range(1, M * 2 + 1):\n",
    "                # 剩余石子减去对方最优策略\n",
    "                best = max(best, s[i] - dfs(i + x, max(x, M)))\n",
    "            # 记忆化\n",
    "            memo[(i, M)] = best\n",
    "            return best\n",
    "        \n",
    "        return dfs(0, 1)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "        sum = [0] * n\n",
    "        for i in range(n - 1, -1, -1):\n",
    "            if i == n - 1:\n",
    "                sum[i] = piles[i]\n",
    "            else:\n",
    "                sum[i] = sum[i + 1] + piles[i]\n",
    "        dp = [[0] * (2 * n) for _ in range(n)]\n",
    "        \n",
    "        def dfs(index, M):\n",
    "            if index == n:\n",
    "                return 0\n",
    "            if n - index <= 2 * M:\n",
    "                return sum[index]\n",
    "            if dp[index][M] != 0:\n",
    "                return dp[index][M]\n",
    "            my_min = float(\"inf\")\n",
    "            for i in range(1, 2 * M + 1):\n",
    "                my_min = min(my_min, dfs(index + i, max(M, i)))\n",
    "            dp[index][M] = sum[index] - my_min\n",
    "            return dp[index][M]\n",
    "\n",
    "        return dfs(0, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        #官方不好理解\n",
    "        # predixsum=[0]\n",
    "        # for pile in piles:\n",
    "        #     predixsum.append(predixsum[-1]+pile)\n",
    "        # #dfs(i,m) 表示前 i 堆石头已经被取走，当前的M=m的情况下，接下去取石头的玩家可以比另一方多取的石头数\n",
    "        # #取走前i堆，剩下的第i+1堆对应的索引就是i\n",
    "        # def dp(i,m):\n",
    "        #     if i==len(piles):\n",
    "        #         return 0\n",
    "        #     mx=-inf\n",
    "        #     for x in range(1,2*m+1):\n",
    "        #         if i+x>len(piles):\n",
    "        #             break\n",
    "        #         mx=max(mx,predixsum[i+x]-predixsum[i]-dp(i+x,max(x,m)))\n",
    "        #     return mx\n",
    "        # return int((predixsum[-1]+dp(0,1))/2)\n",
    "\n",
    "        #解释版本,相对好理解\n",
    "        #dfs(i,m) 表示前 i 堆石头已经被取走（取走前i堆，剩下的第i+1堆对应的索引就是i），当前的M=m的情况下，接下去取石头的玩家获得最大收益\n",
    "        #当前双方已经取走了前i堆石子，还剩下[i, len - 1]堆石子\n",
    "        # 那么我们希望知道在当前的M，我们从这[i, len - 1]堆石子能得到的最大收益，即获取到的最多石子是有多少。\n",
    "        #1.首先明确一个计算公式，我们从位置i取走X堆石子，取走的是[i, i + X - 1]范围的石子，还剩下[i + X , len - 1]堆石子。\n",
    "        #2.如果我们基于当前的M值可以把[i, len - 1]全部取完，那么最大值就是全部取完的值。也就是说i + X - 1 >= len - 1的时候取走了所有的石子。只要最大的X = 2*m满足这个条件即可，即i + 2 * m >= len；\n",
    "        #3.否则我们只能去枚举X ∈ {1， 2*m]的每一种情况，去看我们取走的是[i, i + X - 1]范围的石子之后对手的最大收益是多少。【当前剩余的石子范围变成了[i + X , len - 1]，，M变成max(X, m)，那么对手的最大收益就是dfs(i + X, max(X, m))】，我们要选择是这些情况中对手最大收益最小的那个X，我们的收益 = 当前剩下石子总和sum[i, len - 1] - 对手最小的最大收益min{dfs(i + X, max(X, m))}\n",
    "        #我们可以看到不论是两种情况的哪一种，我们都需要当前剩下石子总和sum[i, len - 1]的值，因为我们使用后缀和的方式先把每个位置i的总和sum[i, len - 1]统计下来。 同时递归的过程，很有可能会对同一个i和m的值dfs(i, m)重复调用，因此我们可以使用一个数组cache[i][m]进行记忆，减少时间开销。\n",
    "        n=len(piles)\n",
    "        suffixsum=[0]*(n+1)\n",
    "        for i in range(n-1,-1,-1):\n",
    "            suffixsum[i]=piles[i]+suffixsum[i+1]\n",
    "\n",
    "        cache=[[0]*(2*n) for _ in range(n)]\n",
    "        def dfs(i,m):\n",
    "            if i>=n:\n",
    "                return 0\n",
    "            if (i+2*m-1)>=(n-1):\n",
    "                return suffixsum[i]\n",
    "            if cache[i][m]==0:\n",
    "                minstones=inf\n",
    "                for x in range(1,2*m+1):\n",
    "                    minstones=min(minstones,dfs(i+x,max(x,m)))\n",
    "                cache[i][m]=suffixsum[i]-minstones\n",
    "            return cache[i][m]\n",
    "        return dfs(0,1)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        @cache\n",
    "        def dfs(i, m):\n",
    "            s = sum(piles[i:])\n",
    "            if 2 * m >= -i:\n",
    "                return s\n",
    "            else:\n",
    "                return s - min([dfs(i + x, m)  for x in range(1, m)] + [dfs(i + x, x) for x in range(m, m * 2 + 1)])\n",
    "                \n",
    "        return dfs(-len(piles), 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "        ss = list(accumulate(piles, initial=0))\n",
    "        inf = float('inf')\n",
    "        # print(ss)\n",
    "        @lru_cache(None)\n",
    "        def dfs(idx, M):\n",
    "            if idx >= n: return 0\n",
    "            if n - idx <= M: return ss[n] - ss[idx]\n",
    "            res = inf\n",
    "            for i in range(1, 2*M+1):\n",
    "                res = min(res, dfs(idx+i, max(M, i)))\n",
    "            res = ss[n] - ss[idx] - res\n",
    "            return res\n",
    "        return dfs(0, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "        presum = [0] * (n+1)\n",
    "        for i in range(n-1, -1, -1):\n",
    "            presum[i] = presum[i+1] + piles[i]\n",
    "        @lru_cache(None)\n",
    "        def dfs(i, m):\n",
    "            if i + 2 * m >= n:\n",
    "                return presum[i]\n",
    "            return presum[i] - min(dfs(i+x, max(m, x)) for x in range(1, 2*m+1))\n",
    "        return dfs(0, 1) % (10**9 + 7)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "        s = [0]*(n+1)\n",
    "        for i in range(n-1, -1, -1):\n",
    "            s[i] += s[i+1] + piles[i] # 后缀和\n",
    "\n",
    "        \n",
    "        @cache\n",
    "        def dfs(i, m):\n",
    "            if i+2*m > n:\n",
    "                return s[i]\n",
    "            \n",
    "            res = inf\n",
    "            for j in range(i, i+2*m):\n",
    "                x = j-i+1\n",
    "                res = min(res, dfs(j+1, max(m,x)))\n",
    "            \n",
    "            return s[i] - res \n",
    "        \n",
    "        return dfs(0, 1)\n",
    "\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "        ss = list(accumulate(piles, initial=0))\n",
    "        inf = float('inf')\n",
    "        # print(ss)\n",
    "        @lru_cache(None)\n",
    "        def dfs(idx, M):\n",
    "            if idx >= n: return 0\n",
    "            if n - idx <= M: return ss[n] - ss[idx]\n",
    "            res = inf\n",
    "            for i in range(1, 2*M+1):\n",
    "                res = min(res, dfs(idx+i, max(M, i)))\n",
    "            res = ss[n] - ss[idx] - res\n",
    "            return res\n",
    "        return dfs(0, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        t=len(piles)\n",
    "        ww={}\n",
    "        for i in range(t-2,-1,-1):\n",
    "            piles[i]+=piles[i+1]\n",
    "        @cache\n",
    "        def dfs(x,m):\n",
    "            if t-x<=2*m:\n",
    "                return piles[x]\n",
    "            return piles[x]-min(dfs(i + x, max(m, i)) for i in range(1, m * 2 + 1))\n",
    "        return dfs(0,1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "        for i in range(n - 2, -1, -1):\n",
    "            piles[i] += piles[i + 1]\n",
    "        @cache\n",
    "        def dfs(i: int, m: int) -> int:\n",
    "            if i + m * 2 >= n:\n",
    "                return piles[i]\n",
    "            return piles[i] - min(dfs(i + x, max(m, x)) for x in range(1, m * 2 + 1))\n",
    "        return dfs(0, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, s: List[int]) -> int:\n",
    "        n = len(s)\n",
    "        for i in range(n - 2, -1, -1):\n",
    "            s[i] += s[i + 1]  # 后缀和\n",
    "\n",
    "        @cache\n",
    "        def dfs(i: int, m: int) -> int:\n",
    "            if i + m * 2 >= n:  # 能全拿\n",
    "                return s[i]\n",
    "            return s[i] - min(dfs(i + x, max(m, x)) for x in range(1, m * 2 + 1))\n",
    "        return dfs(0, 1)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "        for i in range(n - 2,-1,-1):\n",
    "            piles[i] += piles[i + 1]\n",
    "        @cache\n",
    "        def dfs(i,m) -> int:\n",
    "            if i + m * 2 >= n:\n",
    "                return piles[i]\n",
    "            mn = inf\n",
    "            for j in range(1,2 * m + 1):\n",
    "                mn = min(mn,dfs(i + j,max(m,j)))\n",
    "            return piles[i] - mn\n",
    "        return dfs(0,1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "        sufsum = [0] * n\n",
    "        sufsum[-1] = piles[-1]\n",
    "        for i in range(n - 2,-1,-1):\n",
    "            sufsum[i] = sufsum[i + 1] + piles[i]\n",
    "        @cache\n",
    "        def dfs(i,m) -> int:\n",
    "            if i + m * 2 >= n:\n",
    "                return sufsum[i]\n",
    "            mn = inf\n",
    "            for j in range(1,2 * m + 1):\n",
    "                mn = min(mn,dfs(i + j,max(m,j)))\n",
    "            return sufsum[i] - mn\n",
    "        return dfs(0,1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "        for i in range(n - 2, -1, -1):\n",
    "            piles[i] += piles[i + 1]\n",
    "        \n",
    "        @cache\n",
    "        def dfs(left, M):\n",
    "            if left + M * 2 >= n:\n",
    "                return piles[left]\n",
    "            return piles[left] - min(dfs(left + x, max(x, M)) for x in range(1, 2 * M + 1))\n",
    "        return dfs(0, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "\n",
    "        pre = [0]\n",
    "        for a in piles:\n",
    "            pre.append(pre[-1]+a)\n",
    "\n",
    "        n = len(piles)\n",
    "        @lru_cache(cache)\n",
    "        def dp(i, m):\n",
    "            if i==n:\n",
    "                return 0\n",
    "            mx = -inf \n",
    "            for k in range(1, 2*m+1):\n",
    "                if i+k > n:\n",
    "                    break\n",
    "                mx = max(mx, pre[i+k]-pre[i]-dp(i+k, max(m,k)))\n",
    "            return mx \n",
    "        return (dp(0, 1) + pre[-1]) // 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        @cache\n",
    "        def dfs(u, M):\n",
    "            if u > n: return 0\n",
    "            ans = -inf\n",
    "            s = 0\n",
    "            for i in range(u, min(n + 1, u + 2 * M)):\n",
    "                s += piles[i - 1]\n",
    "                ans = max(ans, s - dfs(i + 1, max(i - u + 1, M)))\n",
    "            return ans\n",
    "        \n",
    "        n = len(piles)\n",
    "        return dfs(1, 1) + sum(piles) >> 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, s: List[int]) -> int:\n",
    "        n=len(s)\n",
    "        for i in range(n-2,-1,-1):\n",
    "            s[i] += s[i+1]\n",
    "        @cache\n",
    "        def dfs(i,m):\n",
    "            if i+2*m>=n:\n",
    "                return s[i]\n",
    "            return s[i]-min(dfs(i+x,max(m,x)) for x in range(1,m*2+1))\n",
    "        return dfs(0,1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n=len(piles)\n",
    "        #对抗思想、GNN网络\n",
    "        #求后缀和\n",
    "        s=[0]*n\n",
    "        s[-1]=piles[-1]\n",
    "        for i in range(n-2,-1,-1):\n",
    "            s[i]=s[i+1]+piles[i]\n",
    "        #只考虑了A并没有考虑B，需要A和B都是以最优方式拿石子\n",
    "        @cache\n",
    "        def dfs(i,x):\n",
    "            if n-i<=2*x:\n",
    "                return s[i]\n",
    "            return s[i]-min(dfs(i+k,max(k,x)) for k in range(1,2*x+1))\n",
    "        return dfs(0,1)   \n",
    "                \n",
    "                "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n=len(piles)\n",
    "        m=1\n",
    "        for i in range(n-2,-1,-1):\n",
    "            piles[i]+=piles[i+1]\n",
    "        \n",
    "        @cache\n",
    "        def dfs(i:int, m:int)-> int:\n",
    "            if i+m*2>=n:\n",
    "                return piles[i]\n",
    "            \n",
    "            return piles[i]-min(dfs(i+x,max(m,x)) for x in range(1,m*2+1))\n",
    "        return dfs(0,1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        @cache\n",
    "        def dfs(i, m):\n",
    "            if m * 2 >= n - i:\n",
    "                return s[n] - s[i]\n",
    "            return max(s[n] - s[i] - dfs(i + x, max(m, x)) for x in range(1, m << 1 | 1))\n",
    "\n",
    "        n = len(piles)\n",
    "        s = list(accumulate(piles, initial=0))\n",
    "        return dfs(0, 1)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        \n",
    "        prefixSum = [0]\n",
    "        for a in piles:\n",
    "            prefixSum.append(prefixSum[-1] + a)\n",
    "        \n",
    "        @lru_cache(None)\n",
    "        def dp(i, m):\n",
    "            if i == len(piles):\n",
    "                return 0\n",
    "            mx = -inf\n",
    "            for x in range(1, 2 * m + 1):                \n",
    "                if i+x > len(piles):\n",
    "                    break\n",
    "                mx = max(mx, prefixSum[i + x] - prefixSum[i] - dp(i + x, max(m, x)))\n",
    "            return mx\n",
    "            \n",
    "        return (prefixSum[-1]+dp(0, 1)) // 2\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        n = len(piles)\n",
    "        s = list(accumulate(piles, initial=0))\n",
    "\n",
    "        @cache\n",
    "        def dfs(i, m):\n",
    "            if i >= n:\n",
    "                return 0\n",
    "            ans = -inf\n",
    "            for x in range(1, 2 * m + 1):\n",
    "                if i + x > n:\n",
    "                    break\n",
    "                ans = max(ans, s[i + x] - s[i] - dfs(i + x, max(m, x)))\n",
    "            return ans\n",
    "\n",
    "        return (sum(piles) + dfs(0, 1)) // 2\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import sys\n",
    "from functools import lru_cache\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: [int]) -> int:\n",
    "        total=sum(piles)\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def dfs(ll: int, rr: int, M:int):\n",
    "            if ll+2*M-1>=rr:\n",
    "                return sum(piles[ll::])\n",
    "\n",
    "            maxed=-sys.maxsize\n",
    "            cur=0\n",
    "            tot=0\n",
    "            while ll+cur<=rr and cur+1<=2*M:\n",
    "                tot+=piles[ll+cur]\n",
    "                maxed=max(maxed,tot-dfs(ll+cur+1,rr,max(cur+1,M)))\n",
    "                cur+=1\n",
    "            print(ll,rr,M,maxed)\n",
    "            return maxed\n",
    "\n",
    "        ali=dfs(0,len(piles)-1,1)\n",
    "#        print(ali,total)\n",
    "        return (ali+total)//2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        prefixSum = [0]\n",
    "        for a in piles:\n",
    "            prefixSum.append(prefixSum[-1] + a)\n",
    "        \n",
    "        @lru_cache(None)\n",
    "        def dp(i, m):\n",
    "            if i == len(piles):\n",
    "                return 0\n",
    "            mx = -inf \n",
    "            for x in range(1, 2 * m + 1):\n",
    "                if i + x > len(piles):\n",
    "                    break \n",
    "                mx = max(mx, prefixSum[i + x] - prefixSum[i] - dp(i + x, max(m, x)))\n",
    "            return mx \n",
    "        \n",
    "        return (prefixSum[-1] + dp(0, 1)) // 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from functools import lru_cache\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        pre = [0]\n",
    "        for pile in piles:\n",
    "            pre.append(pre[-1]+pile)\n",
    "        n = len(piles)\n",
    "        @lru_cache(None)\n",
    "        def dp(i, m):\n",
    "            #从index=i开始取\n",
    "            if i == n:\n",
    "                return 0\n",
    "            mx = -inf\n",
    "            for k in range(1, 2*m+1):\n",
    "                 #i+k为下一次开始取的index\n",
    "                if i+k > n:\n",
    "                    break\n",
    "                mx = max(mx, pre[i+k] - pre[i] - dp(i+k, max(m, k)))\n",
    "            return mx\n",
    "\n",
    "        return (dp(0, 1)+pre[-1])//2\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        from functools import lru_cache\n",
    "        # prefix_sum = [0]\n",
    "        # for a in piles:\n",
    "        #     prefix_sum.append(prefix_sum[-1] + a)\n",
    "        \n",
    "        # @lru_cache(None)\n",
    "        # def dp(i, m):\n",
    "        #     if i == len(piles):\n",
    "        #         return 0\n",
    "        #     mx = -10**5\n",
    "        #     for x in range(1, 2 * m + 1):\n",
    "        #         if i + x > len(piles):\n",
    "        #             break\n",
    "        #         mx = max(mx, prefix_sum[i+x] - prefix_sum[i] - dp(i + x, max(m, x)))\n",
    "        #     return mx\n",
    "        # return (prefix_sum[-1]+dp(0, 1)) // 2\n",
    "        \n",
    "        prefix_sum = [0]\n",
    "        for n in piles:\n",
    "            prefix_sum.append(prefix_sum[-1] + n)\n",
    "        \n",
    "        @lru_cache(None)\n",
    "        def dp(i, m):\n",
    "            if i == len(piles):\n",
    "                return 0\n",
    "            mx = -10**5\n",
    "            for x in range(1, 2*m + 1):\n",
    "                if i + x > len(piles):\n",
    "                    break\n",
    "                mx = max(mx, prefix_sum[i + x] - prefix_sum[i] - dp(i+x, max(m, x)))\n",
    "            return mx\n",
    "        return (prefix_sum[-1] + dp(0, 1)) // 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        pre = [0]\n",
    "        for a in piles:\n",
    "            pre.append(pre[-1]+a)\n",
    "        \n",
    "        n = len(piles)\n",
    "\n",
    "        @lru_cache(cache)\n",
    "        def dp(i, m):\n",
    "            if i==n:\n",
    "                return 0\n",
    "            mx = -inf \n",
    "            for k in range(1, 2*m+1):\n",
    "                if i+k > n:\n",
    "                    break\n",
    "                mx = max(mx, pre[i+k]-pre[i]-dp(i+k, max(m,k)))\n",
    "            return mx \n",
    "        return (dp(0, 1) + pre[-1]) // 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "#记忆化搜索 or 动态规划\n",
    "#时间复杂度O(n^3)，其中O(n^2)为状态数，O(n)为计算每个状态结果所用的时间\n",
    "#空间复杂度O(n^2)\n",
    "from functools import cache\n",
    "class Solution:\n",
    "    def stoneGameII(self, s: List[int]) -> int:\n",
    "        n = len(s)\n",
    "        if n<=2:\n",
    "            return sum(s)\n",
    "        prefix = [0]*(n+1)\n",
    "        for i in range(1, n+1):\n",
    "            prefix[i] = prefix[i-1]+s[i-1]\n",
    "        @cache\n",
    "        def dfs(i, m):\n",
    "            if 2*m>=(n-i):\n",
    "                return prefix[-1]-prefix[i]\n",
    "            res = prefix[-1]-prefix[i]-min(dfs(j, max(m, j-i)) for j in range(i+1, i+2*m+1))\n",
    "            return res\n",
    "        return dfs(0, 1)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameII(self, piles: List[int]) -> int:\n",
    "        \n",
    "        prefixSum = [0]\n",
    "        for a in piles:\n",
    "            prefixSum.append(prefixSum[-1] + a)\n",
    "        \n",
    "        @lru_cache(None)\n",
    "        def dp(i, m):\n",
    "            if i == len(piles):\n",
    "                return 0\n",
    "            mx = -inf\n",
    "            for x in range(1, 2 * m + 1):                \n",
    "                if i+x > len(piles):\n",
    "                    break\n",
    "                mx = max(mx, prefixSum[i + x] - prefixSum[i] - dp(i + x, max(m, x)))\n",
    "            return mx\n",
    "            \n",
    "        return (prefixSum[-1]+dp(0, 1)) // 2\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        n = len(stoneValue)\n",
    "        opti = [None] * (n+1) # 存储当剩余位数为idx时最优能赢多少\n",
    "        opti[-1] = 0 # 最后选完了没得选（为了索引不报错）\n",
    "        for idx in range(n-1,-1,-1):\n",
    "            if idx == n-1:\n",
    "                opti[idx] = stoneValue[idx]\n",
    "            elif idx == n-2:\n",
    "                opti[idx] = max(stoneValue[idx] - opti[idx+1], sum(stoneValue[idx:]))\n",
    "            else:\n",
    "                opti[idx] = stoneValue[idx] - opti[idx+1]\n",
    "                opti[idx] = max(opti[idx],sum(stoneValue[idx:idx+2])-opti[idx+2])\n",
    "                opti[idx] = max(opti[idx],sum(stoneValue[idx:idx+3])-opti[idx+3])\n",
    "        if opti[0] > 0:\n",
    "            return \"Alice\" \n",
    "        elif opti[0] < 0:\n",
    "            return 'Bob'\n",
    "        else:\n",
    "            return \"Tie\"\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, a: List[int]) -> str:\n",
    "        \"\"\"\n",
    "        dp[i][player] 表示输入为 stoneValue[i:] 的时候，当前玩家为 player 的时候\n",
    "                         Alice 能够拿到的最大得分\n",
    "        dp[i][alice] = max(\n",
    "            a[i] + dp[i + 1][bob],\n",
    "            a[i] + a[i + 1] + dp[i + 2][bob],\n",
    "            a[i] + a[i + 1] + a[i + 2] + dp[i + 3][bob],\n",
    "        )\n",
    "        dp[i][bob] = min(\n",
    "            dp[i + 1][alice],\n",
    "            dp[i + 2][alice],\n",
    "            dp[i + 3][alice],\n",
    "        )\n",
    "        base case:\n",
    "            dp[n - 1][alice] = a[-1]\n",
    "            dp[n - 1][bob] = 0\n",
    "        \"\"\"\n",
    "        n = len(a)\n",
    "        dp = [[-float(\"inf\"), float(\"inf\")] for i in range(n)]\n",
    "        alice, bob = 0, 1\n",
    "        dp[-1][alice] = a[-1]\n",
    "        dp[-1][bob] = 0\n",
    "        for i in reversed(range(n - 1)):\n",
    "            dp[i][alice] = max(\n",
    "                a[i] + dp[i + 1][bob],\n",
    "                a[i] + a[i + 1] + (dp[i + 2][bob] if i + 2 < n else 0),\n",
    "                a[i] + a[i + 1] + (a[i + 2] if i + 2 < n else 0) + (dp[i + 3][bob] if i + 3 < n else 0),\n",
    "            )\n",
    "            dp[i][bob] = min(\n",
    "                dp[i + 1][alice],\n",
    "                (dp[i + 2][alice] if i + 2 < n else 0),\n",
    "                (dp[i + 3][alice] if i + 3 < n else 0),\n",
    "            )\n",
    "        print(dp)\n",
    "        alice = dp[0][alice]\n",
    "        bob = sum(a) - alice\n",
    "        if alice > bob:\n",
    "            return \"Alice\"\n",
    "        elif alice == bob:\n",
    "            return \"Tie\"\n",
    "        else:\n",
    "            return \"Bob\"\n",
    "            \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        import numpy as np\n",
    "        f = [0 for _ in range(len(stoneValue) + 1)]\n",
    "        _sum = [0 for _ in range(len(stoneValue) + 1)]\n",
    "        for i in [len(stoneValue) - x - 1 for x in range(len(stoneValue))]:\n",
    "            _sum[i] = _sum[i + 1] + stoneValue[i]\n",
    "#             print (_sum[i + 1], sum(stoneValue[i+1:]))\n",
    "            f[i] = stoneValue[i] + _sum[i + 1] - f[i+1]\n",
    "            for j in range(2, 4):\n",
    "                if i + j >= len(stoneValue) + 1:\n",
    "                    break\n",
    "                f[i] = max(f[i], sum(stoneValue[i:i+j]) + _sum[i+j] - f[i+j])\n",
    "#         print (f[0], sum(stoneValue) - f[0])\n",
    "        if f[0] * 2 > sum(stoneValue):\n",
    "            return 'Alice'\n",
    "        if f[0] * 2 == sum(stoneValue):\n",
    "            return 'Tie'\n",
    "        return 'Bob'\n",
    "                "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        dp = [[[0, 0, 0], [0, 0, 0]] for i in range(len(stoneValue)+3)]\n",
    "        s = 0\n",
    "        for i in range(len(stoneValue)-1, -1, -1):\n",
    "            s += stoneValue[i]\n",
    "            dp[i][0][0] = s - max(dp[i+1][1])\n",
    "            dp[i][0][1] = s - max(dp[i+2][1])\n",
    "            dp[i][0][2] = s - max(dp[i+3][1])\n",
    "            dp[i][1][0] = s - max(dp[i+1][0])\n",
    "            dp[i][1][1] = s - max(dp[i+2][0])\n",
    "            dp[i][1][2] = s - max(dp[i+3][0])\n",
    "        for i in (0, 1, 2):\n",
    "            if dp[0][0][i] * 2 > s:\n",
    "                return \"Alice\"\n",
    "        if dp[0][0][0] * 2 == s or dp[0][0][1] * 2 == s or dp[0][0][2] * 2 == s:\n",
    "            return \"Tie\"\n",
    "        return \"Bob\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def __init__(self) -> None:\n",
    "        self.cache = None\n",
    "        self.stoneValue = None\n",
    "\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        self.cache = {}\n",
    "        self.stoneValue = stoneValue\n",
    "        ans = self._search(pos=0)\n",
    "        if ans > 0:\n",
    "            return 'Alice'\n",
    "        elif ans < 0:\n",
    "            return 'Bob'\n",
    "\n",
    "        return 'Tie'\n",
    "\n",
    "    def _search(self, pos: int) -> None:\n",
    "        if pos in self.cache:\n",
    "            return self.cache[pos]\n",
    "\n",
    "        left = len(self.stoneValue) - pos\n",
    "        if left == 1:\n",
    "            take_one = self.stoneValue[pos]\n",
    "            self.cache[pos] = take_one\n",
    "        elif left == 2:\n",
    "            take_two = self.stoneValue[pos] + self.stoneValue[pos+1]\n",
    "            take_one = self.stoneValue[pos] - self._search(pos=pos+1)\n",
    "            self.cache[pos] = max(take_two, take_one)\n",
    "        elif left == 3:\n",
    "            take_three = self.stoneValue[pos] + self.stoneValue[pos+1] + self.stoneValue[pos+2]\n",
    "            take_two = self.stoneValue[pos] + self.stoneValue[pos+1] - self._search(pos=pos+2)\n",
    "            take_one = self.stoneValue[pos] - self._search(pos=pos+1)\n",
    "            self.cache[pos] = max(take_three, take_two, take_one)\n",
    "        elif left > 3:\n",
    "            take_three = self.stoneValue[pos] + self.stoneValue[pos+1] + self.stoneValue[pos+2] - self._search(pos=pos+3)\n",
    "            take_two = self.stoneValue[pos] + self.stoneValue[pos+1] - self._search(pos=pos+2)\n",
    "            take_one = self.stoneValue[pos] - self._search(pos=pos+1)\n",
    "            self.cache[pos] = max(take_three, take_two, take_one)\n",
    "        \n",
    "        return self.cache[pos]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        self.stoneValue = stoneValue\n",
    "        self.dp = [1001] * len(stoneValue)\n",
    "        score = self.helper(0)\n",
    "        # print(self.dp)\n",
    "        # print(score)\n",
    "        if score == 0:\n",
    "            return 'Tie'\n",
    "        elif score > 0:\n",
    "            return 'Alice' \n",
    "        else:\n",
    "            return 'Bob'\n",
    "    \n",
    "    def helper(self, i):\n",
    "        if self.dp[i] <= 1000:\n",
    "            pass\n",
    "        elif i == len(self.dp)-1:\n",
    "            self.dp[i] = self.stoneValue[i]\n",
    "        elif i == len(self.dp)-2:\n",
    "            self.dp[i] =  max(sum(self.stoneValue[-2:]), self.stoneValue[-2]-self.helper(i+1))\n",
    "        elif i == len(self.dp)-3:\n",
    "            self.dp[i] = max(sum(self.stoneValue[-3:]), sum(self.stoneValue[-3:-1])-self.helper(i+2),self.stoneValue[-3]-self.helper(i+1))\n",
    "        else:\n",
    "            self.dp[i] = max(self.stoneValue[i] - self.helper(i+1), sum(self.stoneValue[i:i+2]) - self.helper(i+2), sum(self.stoneValue[i:i+3]) - self.helper(i+3))\n",
    "        return self.dp[i]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def dfs(self, stoneValue, presum, i, n):\n",
    "        if i == n - 1:\n",
    "            return stoneValue[n - 1]\n",
    "        if i > n - 1:\n",
    "            return 0\n",
    "        if i in self.vis:\n",
    "            return self.vis[i]\n",
    "\n",
    "        total = presum[n - 1]\n",
    "        if i > 0:\n",
    "            total -= presum[i - 1]\n",
    "\n",
    "        ans = -1e10\n",
    "        for j in range(1, 4):\n",
    "            cnt_ans = total - self.dfs(stoneValue, presum, i + j, n)\n",
    "            ans = max(ans, cnt_ans)\n",
    "        self.vis[i] = ans\n",
    "        return ans\n",
    "\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        self.vis = {}\n",
    "        presum = [stoneValue[0]]\n",
    "        n = len(stoneValue)\n",
    "        for i in range(1, n):\n",
    "            presum.append(presum[-1] + stoneValue[i])\n",
    "\n",
    "        ans = self.dfs(stoneValue, presum, 0, n)\n",
    "        diff = 2 * ans - sum(stoneValue)  # Alice - Bob\n",
    "        if diff > 0:\n",
    "            return 'Alice'\n",
    "        if diff < 0:\n",
    "            return 'Bob'\n",
    "        return 'Tie'\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        n = len(stoneValue)\n",
    "        preSum = list(accumulate(stoneValue, initial=0))\n",
    "        dp = [-inf for _ in range(n + 1)]\n",
    "        dp[n] = 0\n",
    "        for i in range(n - 1, -1, -1):\n",
    "            for c in range(1, 4):\n",
    "                if i + c <= n:\n",
    "                    dp[i] = max(dp[i], preSum[-1] - preSum[i] - dp[i + c])\n",
    "        \n",
    "        # 从 i 开始\n",
    "        @cache\n",
    "        def dfs(i: int) -> int:\n",
    "            if i == n:\n",
    "                return 0\n",
    "            val = -inf\n",
    "            # 模拟选择 3 堆，取最大得分\n",
    "            for c in range(1, 4):\n",
    "                if i + c <= n:\n",
    "                    val = max(val, preSum[-1] - preSum[i] - dfs(i + c))\n",
    "            return val\n",
    "        a = dp[0]\n",
    "        b = preSum[-1] - a\n",
    "        #print(a, b)\n",
    "        return 'Alice' if a > b else 'Bob' if a < b else 'Tie'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def dfs(self, stoneValue, memo, idx):\n",
    "        if idx == len(stoneValue): return 0\n",
    "        if memo[idx] != None: return memo[idx]\n",
    "\n",
    "        ans = -float('inf')\n",
    "        cur = idx\n",
    "        score = 0\n",
    "        while cur < idx + 3 and cur < len(stoneValue):\n",
    "            score += stoneValue[cur]\n",
    "            ans = max(ans, score - self.dfs(stoneValue, memo, cur + 1))\n",
    "            cur += 1\n",
    "        \n",
    "        memo[idx] = ans\n",
    "        return ans\n",
    "\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        n = len(stoneValue)\n",
    "        memo = [None] * n\n",
    "        score = self.dfs(stoneValue, memo, 0)\n",
    "        if score > 0:\n",
    "            return \"Alice\"\n",
    "        elif score < 0:\n",
    "            return \"Bob\"\n",
    "        else:\n",
    "            return \"Tie\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "\n",
    "        n = len(stoneValue)\n",
    "        s = [0 for _ in range(n+1)]\n",
    "        for i in range(n-1,-1,-1):\n",
    "            s[i] = s[i+1] + stoneValue[i]\n",
    "\n",
    "        mx = [0 for _ in range(n+1)]\n",
    "        def dfs(idx):\n",
    "            if idx == n: return 0 \n",
    "            \n",
    "            opposite = []\n",
    "            for i in range(1,4):\n",
    "                if idx+i <= n:\n",
    "                    if mx[idx+i] == 0:\n",
    "                        mx[idx+i] = dfs(idx+i)\n",
    "                    opposite.append(mx[idx+i])\n",
    "\n",
    "            res = s[idx] - min(opposite)\n",
    "            mx[idx] = res\n",
    "            return res\n",
    "\n",
    "        a = dfs(0)\n",
    "        b = s[0] - a\n",
    "\n",
    "        ''' '''\n",
    "        if a>b: return \"Alice\"\n",
    "        elif a==b: return \"Tie\"\n",
    "        else: return \"Bob\" \n",
    "        \n",
    "        # return mx\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        score = [None] * len(stoneValue)\n",
    "        start = 0\n",
    "        \n",
    "        def game(stonevalues, start):\n",
    "            values = stonevalues\n",
    "            if(start >= len(values)):\n",
    "                return 0\n",
    "            if(score[start] != None): return score[start]\n",
    "            if(start <= len(values) - 1):\n",
    "                v = values[start] - game(values, start+1)\n",
    "            if(start + 1 <= len(values) - 1):\n",
    "                v = max(v, values[start] + values[start+1] - game(values, start+2))\n",
    "            if(start + 2 <= len(values) - 1):\n",
    "                v = max(v, values[start] + values[start+1] + values[start+2] - game(values, start+3))\n",
    "            score[start] = v\n",
    "            return v\n",
    "            \n",
    "        res = game(stoneValue, 0)\n",
    "        if(res > 0): return \"Alice\"\n",
    "        elif(res < 0): return \"Bob\"\n",
    "        else: return \"Tie\"\n",
    "\n",
    "        '''\n",
    "        n =len(stoneValue)\n",
    "        @cache\n",
    "        def dfs(i):\n",
    "            if i >=n:\n",
    "                return 0\n",
    "            ans =-1\n",
    "            if i+1<=n:\n",
    "                ans = max(ans,stoneValue[i]-dfs(i+1))\n",
    "            if i+2<=n:\n",
    "                ans = max(ans,stoneValue[i]+stoneValue[i+1]-dfs(i+2))\n",
    "            if i+3<=n:\n",
    "                ans = max(ans,stoneValue[i]+stoneValue[i+1]+stoneValue[i+2]-dfs(i+3))\n",
    "            return ans \n",
    "        \n",
    "        t = dfs(0)\n",
    "        if t>0:return 'Alice'\n",
    "        elif t<0:return 'Bob'\n",
    "        else:return 'Tie'\n",
    "        '''\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        n = len(stoneValue)\n",
    "        @cache\n",
    "        def back(l):\n",
    "            if l == n:return 0\n",
    "            res = -inf\n",
    "            lin = 0\n",
    "            for i in range(1,min(4,n-l+1)):\n",
    "                lin += stoneValue[l+i-1]\n",
    "                res = max(res,lin-back(l+i))\n",
    "            return res\n",
    "        res = back(0)\n",
    "        del back\n",
    "        if res > 0:\n",
    "            return \"Alice\"\n",
    "        elif res == 0:\n",
    "            return \"Tie\"\n",
    "        else:\n",
    "            return \"Bob\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        acc = list(accumulate(stoneValue, initial=0))\n",
    "        n = len(stoneValue)\n",
    "        @cache\n",
    "        def f(i):\n",
    "            if i == n:\n",
    "                return [0, 0]\n",
    "            if i == n - 1:\n",
    "                return [stoneValue[-1], 0]\n",
    "            choice = min(n - i, 3)\n",
    "            res = -inf\n",
    "            for j in range(1, choice + 1):\n",
    "                fir, sec = f(i + j)\n",
    "                res = max(res, sum(stoneValue[i: i + j]) + sec)\n",
    "            return [res, acc[n] - acc[i] - res]\n",
    "        a, b = f(0)\n",
    "        if a > b: return \"Alice\"\n",
    "        elif a < b: return \"Bob\"\n",
    "        return \"Tie\"\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        memo=defaultdict(int)\n",
    "        n=len(stoneValue)\n",
    "\n",
    "        def dp(i,memo):\n",
    "            if i>=n:\n",
    "                return 0\n",
    "            if memo[i]:\n",
    "                return memo[i]\n",
    "            memo[i]=-inf\n",
    "            for j in range(1,4):\n",
    "                \n",
    "                memo[i]=max(memo[i],sum(stoneValue[i:i+j])-dp(i+j,memo))\n",
    "               \n",
    "\n",
    "            return memo[i]\n",
    "\n",
    "        ans=dp(0,memo)\n",
    "\n",
    "        if ans>0:\n",
    "            return \"Alice\"\n",
    "        elif ans==0:\n",
    "            return \"Tie\"\n",
    "        return \"Bob\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        all_sum = sum(stoneValue)\n",
    "        n = len(stoneValue)\n",
    "        @lru_cache\n",
    "        def dfs(cur):\n",
    "            if cur>=n:return 0 #<0输，=0平,>0胜\n",
    "            res = -dfs(cur+1)+sum(stoneValue[cur:cur+1])\n",
    "            for i in range(2,4):\n",
    "                res = max(res,-dfs(cur+i)+sum(stoneValue[cur:cur+i]))\n",
    "            return res\n",
    "        ans = dfs(0)\n",
    "        if ans==0:return 'Tie'\n",
    "        elif ans>0:return 'Alice'\n",
    "        else:return 'Bob'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        n = len(stoneValue)\n",
    "\n",
    "        # 返回从i开始到结束Alice的得分和Bob的得分\n",
    "        @lru_cache(None)\n",
    "        def f(i, people):\n",
    "            if i == n:\n",
    "                return [0, 0]\n",
    "            if i == n - 1:\n",
    "                tmp = f(i + 1, people * -1)\n",
    "                if people == 1:\n",
    "                    return [stoneValue[i] + tmp[0], tmp[1]]\n",
    "                return [tmp[0], tmp[1] + stoneValue[i]]\n",
    "            elif i == n - 2:\n",
    "                tmp1 = f(i + 1, people * -1)\n",
    "                tmp2 = f(i + 2, people * -1)\n",
    "                if people == 1:\n",
    "                    if stoneValue[i] + tmp1[0] - tmp1[1] > stoneValue[i] + stoneValue[i + 1] + tmp2[0] - tmp2[1]:\n",
    "                        return [stoneValue[i] + tmp1[0], tmp1[1]]\n",
    "                    else:\n",
    "                        return [stoneValue[i] + stoneValue[i + 1] + tmp2[0], tmp2[1]]\n",
    "                else:\n",
    "                    if stoneValue[i] + tmp1[1] - tmp1[0] > stoneValue[i] + stoneValue[i + 1] + tmp2[1] - tmp2[0]:\n",
    "                        return [tmp1[0], stoneValue[i] + tmp1[1]]\n",
    "                    else:\n",
    "                        return [tmp2[0], stoneValue[i] + stoneValue[i + 1] + tmp2[1]]\n",
    "            else:\n",
    "                tmp1 = f(i + 1, people * -1)\n",
    "                tmp2 = f(i + 2, people * -1)\n",
    "                tmp3 = f(i + 3, people * -1)\n",
    "                if people == 1:\n",
    "                    t1 = stoneValue[i] + tmp1[0] - tmp1[1]\n",
    "                    t2 = stoneValue[i] + stoneValue[i + 1] + tmp2[0] - tmp2[1]\n",
    "                    t3 = stoneValue[i] + stoneValue[i + 1] + stoneValue[i + 2] + tmp3[0] - tmp3[1]\n",
    "                    if t3 == max(t1, t2, t3):\n",
    "                        return [stoneValue[i] + stoneValue[i + 1] + stoneValue[i + 2] + tmp3[0], tmp3[1]]\n",
    "                    elif t2 == max(t1, t2, t3):\n",
    "                        return [stoneValue[i] + stoneValue[i + 1] + tmp2[0], tmp2[1]]\n",
    "                    else:\n",
    "                        return [stoneValue[i] + tmp1[0], tmp1[1]]\n",
    "                else:\n",
    "                    t1 = stoneValue[i] + tmp1[1] - tmp1[0]\n",
    "                    t2 = stoneValue[i] + stoneValue[i + 1] + tmp2[1] - tmp2[0]\n",
    "                    t3 = stoneValue[i] + stoneValue[i + 1] + stoneValue[i + 2] + tmp3[1] - tmp3[0]\n",
    "                    if t3 == max(t1, t2, t3):\n",
    "                        return [tmp3[0], stoneValue[i] + stoneValue[i + 1] + stoneValue[i + 2] + tmp3[1]]\n",
    "                    elif t2 == max(t1, t2, t3):\n",
    "                        return [tmp2[0], stoneValue[i] + stoneValue[i + 1] + tmp2[1]]\n",
    "                    else:\n",
    "                        return [tmp1[0], stoneValue[i] + tmp1[1]]\n",
    "\n",
    "        ans = f(0, 1)\n",
    "        if ans[0] > ans[1]:\n",
    "            return \"Alice\"\n",
    "        elif ans[0] == ans[1]:\n",
    "            return \"Tie\"\n",
    "        return \"Bob\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, values: List[int]) -> str:\n",
    "        @lru_cache(None)\n",
    "        def dp(i, p):\n",
    "            if i == len(values):\n",
    "                return 0, 0\n",
    "            s = 0\n",
    "            mx = -inf\n",
    "            mxt = None\n",
    "            for l in range(i, min(len(values), i + 3)):\n",
    "                s += values[l]\n",
    "                t = dp(l + 1, 1 - p)\n",
    "                t = list(t)\n",
    "                t[p] += s\n",
    "                if t[p] > mx:\n",
    "                    mx = t[p]\n",
    "                    mxt = t\n",
    "                elif t[p] == mx and t[1 - p] < mxt[1 - p]:\n",
    "                    mxt = t\n",
    "\n",
    "            return tuple(mxt)\n",
    "\n",
    "        dpa = dp(0, 0)\n",
    "\n",
    "        dp.cache_clear()\n",
    "        \n",
    "        if dpa[0] == dpa[1]:\n",
    "            return 'Tie'\n",
    "        elif dpa[0] > dpa[1]:\n",
    "            return 'Alice'\n",
    "        else:\n",
    "            return 'Bob'\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        s = list(accumulate(stoneValue, initial=0))\n",
    "        n = len(stoneValue)\n",
    "        @lru_cache\n",
    "        def dfs(idx):\n",
    "            # if n - idx <= 3:\n",
    "            #     return min([s[n] - s[idx] for ])\n",
    "            if idx >= n: return 0\n",
    "            return s[n] - s[idx] - min(dfs(idx+1), dfs(idx+2), dfs(idx+3))\n",
    "        res = dfs(0)\n",
    "        if res > s[-1] - res: return \"Alice\"\n",
    "        elif res == s[-1] - res: return \"Tie\"\n",
    "        else: return \"Bob\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        n = len(stoneValue)\n",
    "        pres = list(accumulate(stoneValue, initial=0))\n",
    "        @lru_cache(None)\n",
    "        def dfs(i):\n",
    "            if i >= n:\n",
    "                return 0 \n",
    "            res = max(pres[min(i + 1, n)] - pres[i] - dfs(i + 1), pres[min(i + 2, n)] - pres[i] - dfs(i + 2), pres[min(i + 3, n)] - pres[i] - dfs(i + 3))\n",
    "            return res\n",
    "        res = dfs(0)\n",
    "        dfs.cache_clear()\n",
    "        return 'Alice' if res > 0 else 'Bob' if res < 0 else 'Tie'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, piles: List[int]) -> str:\n",
    "        n = len(piles)\n",
    "        dp = [0]*(n+1) #从当前位置到最后数组和\n",
    "        for i in range(n-1,-1,-1):\n",
    "            dp[i] = dp[i+1]+piles[i]\n",
    "        @lru_cache(None)\n",
    "        def dfs(left): #当从第 left 堆石子开始拿，允许拿 M <= x <= 2 * M 时，在剩余石子中所能拿到的最大值\n",
    "            if left>n:\n",
    "                return 0\n",
    "            ans = float('-inf')\n",
    "            for x in range(1,4):\n",
    "                ans = max(ans,dp[left]-dfs(left+x) )\n",
    "            return ans\n",
    "        ans = dfs(0)\n",
    "        dfs.cache_clear()\n",
    "        if ans*2>dp[0]:return 'Alice'\n",
    "        elif ans*2<dp[0]:return 'Bob'\n",
    "        return 'Tie'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        suffix = stoneValue\n",
    "        for i in range(len(stoneValue)-2, -1, -1):\n",
    "            suffix[i] += suffix[i+1]\n",
    "        @cache\n",
    "        def dfs(i):\n",
    "            if i >= len(stoneValue):\n",
    "                return 0\n",
    "            return suffix[i] - min(dfs(i + x) for x in range(1,4))\n",
    "             \n",
    "        if 2 * dfs(0) == suffix[0]: return 'Tie'\n",
    "        return 'Bob' if 2 * dfs(0) < suffix[0] else 'Alice'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, nums: List[int]) -> str:\n",
    "        n=len(nums)\n",
    "        su=sum(nums)\n",
    "        s=[0]*n\n",
    "        s[-1]=nums[-1]\n",
    "        for i in range(n-2,-1,-1):\n",
    "            s[i]=s[i+1]+nums[i]\n",
    "        @cache\n",
    "        def dfs(i):\n",
    "            if i>=n:\n",
    "                return 0\n",
    "            return s[i]-min(dfs(i+k) for k in range(1,4))\n",
    "        if su-dfs(0)>dfs(0):\n",
    "            return 'Bob'\n",
    "        elif su-dfs(0)<dfs(0):\n",
    "            return 'Alice'\n",
    "        else :\n",
    "            return 'Tie'\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        n = len(stoneValue)\n",
    "        sm = list(accumulate(stoneValue, initial=0))\n",
    "        \n",
    "        @cache\n",
    "        def first(i: int, j: int) -> int:\n",
    "            # if j - i + 1 <= 3:\n",
    "            #     return sum(stoneValue[i:j+1])\n",
    "            # 先手必须选择一个石头\n",
    "            # 越界没得选\n",
    "            if i > j:\n",
    "                return 0\n",
    "            res = stoneValue[i] + second(i + 1, j)\n",
    "            for k in range(3):\n",
    "                if k + i > j: break\n",
    "                res = max(res, second(i + k + 1, j) + sm[i + k + 1] - sm[i])\n",
    "            return res\n",
    "        \n",
    "        @cache\n",
    "        def second(i: int, j: int) -> int:\n",
    "            # 越界你后手代表没得选\n",
    "            res = inf if j >= i else 0\n",
    "            for k in range(3):\n",
    "                if k + i > j: break\n",
    "                res = min(first(i + k + 1, j), res)\n",
    "            return res\n",
    "        s1, s2 = first(0, n - 1), second(0, n - 1)\n",
    "        first.cache_clear()\n",
    "        second.cache_clear()\n",
    "        if s1 > s2:\n",
    "            return 'Alice'\n",
    "        elif s1 < s2:\n",
    "            return 'Bob'\n",
    "        return 'Tie'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        @cache\n",
    "        def dp(i: int) -> int:\n",
    "            return max((sum(stoneValue[i:j + 1]) - dp(j + 1) for j in range(i, min(i + 3, len(stoneValue)))), default=0)\n",
    "\n",
    "        score = dp(0)\n",
    "        return \"Alice\" if score > 0 else \"Bob\" if score < 0 else \"Tie\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str: \n",
    "        n = len(stoneValue)\n",
    "        f = [inf] * n\n",
    "        s = [0] * (n + 1)\n",
    "        for i in range(1, n + 1):\n",
    "            s[i] = s[i - 1] + stoneValue[i - 1]\n",
    "        def dfs(x):\n",
    "            if f[x] != inf: return f[x]\n",
    "            if x == n - 1:\n",
    "                f[x] = stoneValue[-1]\n",
    "            elif x == n - 2:\n",
    "                f[x] = max(stoneValue[-2], stoneValue[-2] + stoneValue[-1])\n",
    "            elif x == n - 3:\n",
    "                f[x] = max(stoneValue[-3] + stoneValue[-2] + stoneValue[-1] - dfs(x + 1), stoneValue[-3] + stoneValue[-2], stoneValue[-3] + stoneValue[-2] + stoneValue[-1])\n",
    "            else:\n",
    "                f[x] = s[n] - s[x] - min(dfs(x + 1), dfs(x + 2), dfs(x + 3))\n",
    "            return f[x]\n",
    "        ans = dfs(0)\n",
    "        if ans > s[n] / 2: return 'Alice'\n",
    "        if ans == s[n] / 2: return 'Tie'\n",
    "        if ans < s[n] / 2: return 'Bob'\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from typing import List\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        piles = stoneValue\n",
    "        n = len(piles)\n",
    "        \n",
    "        # Calculate prefix sums\n",
    "        prefix_sum = [0] * (n+1)\n",
    "        for i in range(n-1, -1, -1):\n",
    "            prefix_sum[i] = prefix_sum[i + 1] + piles[i]\n",
    "\n",
    "        # DP array to store results\n",
    "        dp = [float('-inf')] * (n+1)\n",
    "\n",
    "        def dfs(index):\n",
    "            if index >= n:\n",
    "                return 0\n",
    "            if dp[index] != float('-inf'):\n",
    "                return dp[index]\n",
    "\n",
    "            total = 0\n",
    "            for i in range(1, 4):\n",
    "                if index + i - 1 < n:\n",
    "                    total += piles[index + i - 1]\n",
    "                    dp[index] = max(dp[index], total + prefix_sum[index+i] - dfs(index + i))\n",
    "\n",
    "            return dp[index]\n",
    "\n",
    "        temp = dfs(0)\n",
    "        if temp > prefix_sum[0] / 2:\n",
    "            return 'Alice'\n",
    "        elif temp < prefix_sum[0] / 2:\n",
    "            return 'Bob'\n",
    "        else:\n",
    "            return 'Tie'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        n = len(stoneValue)\n",
    "        dic = {}\n",
    "        dic[n - 1] = stoneValue[-1]\n",
    "        dic[n]=0\n",
    "\n",
    "        def dp(m):\n",
    "            if m in dic: return dic[m]\n",
    "            res = 0\n",
    "            if m + 1 <= n:\n",
    "                res = stoneValue[m] - dp(m + 1)\n",
    "            if m + 2 <= n:\n",
    "                res = max(res, stoneValue[m] + stoneValue[m + 1] - dp(m + 2))\n",
    "            if m + 3 <= n:\n",
    "                res = max(res, stoneValue[m] + stoneValue[m + 1] + stoneValue[m + 2] - dp(m + 3))\n",
    "            dic[m] = res\n",
    "            return res\n",
    "\n",
    "        dp(0)\n",
    "        if dic[0] > 0:\n",
    "            return \"Alice\"\n",
    "        elif dic[0] < 0:\n",
    "            return \"Bob\"\n",
    "        return \"Tie\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        memo = {}\n",
    "        def minimax(index):\n",
    "            if index == len(stoneValue):\n",
    "                return 0\n",
    "            if index in memo:\n",
    "                return memo[index]\n",
    "            res = -float(\"inf\")\n",
    "            score = 0\n",
    "            for i in range(index, index+3):\n",
    "                if i < len(stoneValue):\n",
    "                    score += stoneValue[i]\n",
    "                    res = max(res, score - minimax(i+1))\n",
    "            memo[index] = res\n",
    "            return memo[index]\n",
    "\n",
    "        score = minimax(0)\n",
    "        if score == 0:\n",
    "            return \"Tie\"\n",
    "        elif score > 0:\n",
    "            return \"Alice\"\n",
    "        else:\n",
    "            return \"Bob\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        dp = {}\n",
    "        \n",
    "        def dfs(i):\n",
    "            if i >= len(stoneValue):\n",
    "                return 0\n",
    "            if i in dp:\n",
    "                return dp[i]\n",
    "            res = float('-inf')\n",
    "            for j in range(i, min(i + 3, len(stoneValue))):\n",
    "                res = max(res, sum(stoneValue[i:j+1]) - dfs(j + 1))\n",
    "            \n",
    "            dp[i] = res\n",
    "            return dp[i]\n",
    "        alice = dfs(0)\n",
    "        if alice > 0: return 'Alice'\n",
    "        elif alice < 0: return 'Bob'\n",
    "        else: return 'Tie'\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        @cache\n",
    "        def dp(i):\n",
    "            if i >= len(stoneValue): return 0\n",
    "            a1 = stoneValue[i] - dp(i+1)\n",
    "            a2 = stoneValue[i]+stoneValue[i+1] - dp(i+2) if i+1<len(stoneValue) else -inf\n",
    "            a3 = stoneValue[i]+stoneValue[i+1]+stoneValue[i+2] - dp(i+3)if i+2<len(stoneValue) else -inf\n",
    "            return max(a1,a2,a3)\n",
    "        x = dp(0)\n",
    "        if x > 0: return 'Alice'\n",
    "        if x < 0: return 'Bob'\n",
    "        return 'Tie'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: list[int]) -> str:\n",
    "        if not stoneValue:\n",
    "            return 'Tie'\n",
    "        n = len(stoneValue)\n",
    "\n",
    "        @cache\n",
    "        def func1(i):\n",
    "            if i == n:\n",
    "                return 0\n",
    "            D_value = stoneValue[i] - func1(i + 1)\n",
    "            if i + 1 < n:\n",
    "                D_value = max(D_value, sum(stoneValue[i:i + 2]) - func1(i + 2))\n",
    "            if i + 2 < n:\n",
    "                D_value = max(D_value, sum(stoneValue[i:i + 3]) - func1(i + 3))\n",
    "            return D_value\n",
    "\n",
    "        D_value = func1(0)\n",
    "        if D_value > 0:\n",
    "            return 'Alice'\n",
    "        if D_value == 0:\n",
    "            return 'Tie'\n",
    "        return 'Bob'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        n = len(stoneValue)\n",
    "        @cache # 从indx开始能赚多少分\n",
    "        def f(indx):\n",
    "            if indx == n:\n",
    "                return 0\n",
    "            res = -inf\n",
    "            for i in range(1, min(4,n-indx+1)):\n",
    "                res = max(res, sum(stoneValue[indx:indx+i]) - f(indx+i) )\n",
    "            return res\n",
    "        return 'Alice' if f(0)>0 else 'Bob' if f(0)<0 else 'Tie'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        n = len(stoneValue)\n",
    "        # 先手函数\n",
    "        @lru_cache(None)\n",
    "        def f(i: int):\n",
    "            if i >= n:\n",
    "                return 0\n",
    "            if i == n - 1:\n",
    "                return stoneValue[i]\n",
    "            ans = stoneValue[i] + s(i + 1)\n",
    "            if i + 1 < n:\n",
    "                ans = max(ans, stoneValue[i] + stoneValue[i + 1] + s(i + 2))\n",
    "            if i + 2 < n:\n",
    "                ans = max(ans, stoneValue[i] + stoneValue[i + 1] + stoneValue[i + 2] + s(i + 3))\n",
    "            return ans\n",
    "        # 后手函数\n",
    "        @lru_cache(None)\n",
    "        def s(i: int):\n",
    "            if i >= n - 1:\n",
    "                return 0\n",
    "            return min(f(i + 1), f(i + 2), f(i + 3))\n",
    "        \n",
    "        scoreA = f(0)\n",
    "        f.cache_clear()\n",
    "        tot = sum(stoneValue)\n",
    "        scoreB = tot - scoreA\n",
    "        return \"Alice\" if scoreA > scoreB else \"Bob\" if scoreA < scoreB else \"Tie\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        n = len(stoneValue)\n",
    "        h = list(accumulate(stoneValue)) + [0]\n",
    "        @cache\n",
    "        def p(i):\n",
    "            if i == n:\n",
    "                return 0\n",
    "            res = h[i]-h[i-1]-p(i+1)\n",
    "            if i+2 <= n:\n",
    "                res = max(res, h[i+1]-h[i-1]-p(i+2))\n",
    "            if i+3 <= n:\n",
    "                res = max(res, h[i+2]-h[i-1]-p(i+3))\n",
    "            return res\n",
    "        res = p(0)\n",
    "        if res > 0:\n",
    "            return \"Alice\"\n",
    "        elif res < 0:\n",
    "            return \"Bob\"\n",
    "        else:\n",
    "            return \"Tie\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        n = len(stoneValue)\n",
    "        pres = list(accumulate(stoneValue, initial=0))\n",
    "        @cache\n",
    "        def dfs(i):\n",
    "            if i >= n:\n",
    "                return 0 \n",
    "            res = max(pres[min(i + 1, n)] - pres[i] - dfs(i + 1), pres[min(i + 2, n)] - pres[i] - dfs(i + 2), pres[min(i + 3, n)] - pres[i] - dfs(i + 3))\n",
    "            return res\n",
    "        res = dfs(0)\n",
    "        return 'Alice' if res > 0 else 'Bob' if res < 0 else 'Tie'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        # 表示从i到n先手对后手的最大净胜分，结果为dfs(0,n),转移为选择第i,i+1，i+2\n",
    "        @cache\n",
    "        def dfs(i):\n",
    "            if i==n:return 0\n",
    "            res=-inf\n",
    "            for j in range(i,min(i+3,n)):\n",
    "                res=max(res,presum[j+1]-presum[i]-dfs(j+1))\n",
    "            return res \n",
    "        n=len(stoneValue)\n",
    "        presum=list(itertools.accumulate(stoneValue,initial=0))\n",
    "        ans=dfs(0)\n",
    "        if ans>0:\n",
    "            return 'Alice'\n",
    "        elif ans<0:\n",
    "            return 'Bob'\n",
    "        else:\n",
    "            return 'Tie'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        n, memo = len(stoneValue), {}\n",
    "        s = [0]*(n+1)\n",
    "        for i in range(n-1, -1, -1):\n",
    "            s[i] = s[i+1]+stoneValue[i]\n",
    "\n",
    "        def dfs(start):\n",
    "            if start >= n:\n",
    "                return 0\n",
    "            if start in memo:\n",
    "                return memo[start]\n",
    "            res = -float('inf')\n",
    "            for x in range(1, 4):\n",
    "                if start+x > n:\n",
    "                    break\n",
    "                res = max(res, s[start] - dfs(start+x))\n",
    "            memo[start] =res\n",
    "            return res\n",
    "        \n",
    "        Alice = dfs(0)\n",
    "        Bob = s[0] -dfs(0)\n",
    "        #print(Alice, Bob)\n",
    "\n",
    "        if Alice > Bob:\n",
    "            return \"Alice\"\n",
    "        elif Alice < Bob:\n",
    "            return \"Bob\"\n",
    "        else:\n",
    "            return \"Tie\"\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        self.stoneValue = stoneValue\n",
    "        res = self.dfs(0)\n",
    "        if res > 0:\n",
    "            return 'Alice'\n",
    "        elif res < 0:\n",
    "            return 'Bob'\n",
    "        return 'Tie'\n",
    "    \n",
    "    @lru_cache(None)\n",
    "    def dfs(self, index):\n",
    "        if index >= len(self.stoneValue):\n",
    "            return 0\n",
    "        if index == len(self.stoneValue)-1:\n",
    "            return self.stoneValue[-1]\n",
    "        max_val = float('-inf')\n",
    "        for i in range(1, 4):\n",
    "            max_val = max(max_val, sum(self.stoneValue[index:index+i]) - self.dfs(index+i))\n",
    "        return max_val\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from itertools import accumulate\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        \"\"\" DFS-memo \n",
    "        1. dfs(i) ==> current rewards \n",
    "        2. get the prefix Sum of stoneValue preSum \n",
    "        3. \n",
    "        rest_rewards = preSum[-1] - preSum[i]\n",
    "        if state == 1:\n",
    "            ans = rest_rewards - dfs(i+1)\n",
    "        if state == 2 ==> i + 1 < len(stoneValue):\n",
    "            ans = max(ans, rest_rewards - dfs(i+2))\n",
    "        if state = 3 ==> i + 2 < len(stoneValue):\n",
    "            ans = max(ans, rest_rewards - dfs(i+3))\n",
    "        4. termination: if i >= len(stoneValue): return 0 \n",
    "        5. start: dfs(0)\n",
    "        \"\"\"\n",
    "\n",
    "        preSum = list(accumulate(stoneValue, initial=0))\n",
    "        n = len(stoneValue)\n",
    "        # print(preSum)\n",
    "        summ = sum(stoneValue)\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def dfs(i):\n",
    "            if i >= n:\n",
    "                return 0 \n",
    "\n",
    "            rest_rewards = preSum[-1] - preSum[i]\n",
    "            ans = rest_rewards - dfs(i+1)\n",
    "            if i + 1 < n:\n",
    "                ans = max(ans, rest_rewards - dfs(i+2))\n",
    "            if i + 2 < n:\n",
    "                ans = max(ans, rest_rewards - dfs(i+3))\n",
    "\n",
    "            return ans \n",
    "\n",
    "        ans = dfs(0)\n",
    "        if 2*ans > summ:\n",
    "            return \"Alice\"\n",
    "        elif 2*ans < summ:\n",
    "            return \"Bob\"\n",
    "        else:\n",
    "            return \"Tie\"\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        n = len(stoneValue)\n",
    "        pre_sum = list(accumulate(stoneValue, initial = 0))\n",
    "        @cache\n",
    "        def dfs(i):\n",
    "            if i >= n:\n",
    "                return 0\n",
    "            res = -inf\n",
    "            for j in range(1, 4):\n",
    "                res = max(res, pre_sum[-1] - pre_sum[i] - dfs(i + j))\n",
    "            return res\n",
    "        alice = dfs(0)\n",
    "        #print(alice)\n",
    "        if alice * 2 > pre_sum[-1]: return 'Alice'\n",
    "        if alice * 2 == pre_sum[-1]: return 'Tie'\n",
    "        return 'Bob'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:        \n",
    "        n = len(stoneValue)\n",
    "        sum = [0] * (n + 1)\n",
    "        for i in range(n):\n",
    "            sum[i] = sum[i-1] + stoneValue[i]\n",
    "\n",
    "        @cache\n",
    "        def dfs(s):\n",
    "            nonlocal sum, n\n",
    "            if s == n:\n",
    "                return 0\n",
    "            ma = -float('inf')\n",
    "            for x in range(1, 4):\n",
    "                if s + x > n:\n",
    "                    break\n",
    "                ma = max(ma, sum[n - 1] - sum[s-1] - dfs(s + x))\n",
    "            print(s, ma)\n",
    "            return ma\n",
    "                \n",
    "        r = dfs(0)\n",
    "        if r * 2> sum[-2]:\n",
    "            return 'Alice'\n",
    "        elif r * 2 == sum[-2]:\n",
    "            return 'Tie'\n",
    "        else:\n",
    "            return 'Bob'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        total = sum(stoneValue)\n",
    "        memo = {}\n",
    "        n = len(stoneValue)\n",
    "        s = [0]*(n+1)\n",
    "        for i in range(n-1,-1,-1):\n",
    "            s[i]=s[i+1]+ stoneValue[i]\n",
    "        def dp(i):\n",
    "            if i in memo:\n",
    "                return memo[i]\n",
    "            if i>=n:\n",
    "                return 0\n",
    "            best = float('-inf')\n",
    "            for j in range(3):\n",
    "                if i+j<n:\n",
    "                    best = max(best,sum(stoneValue[i:i+j+1])+s[i+j+1]-dp(i+j+1) )\n",
    "            memo[i] = best\n",
    "            return best\n",
    "        ans = dp(0)\n",
    "        if ans*2>total:\n",
    "            return \"Alice\"\n",
    "        if ans*2==total:\n",
    "            return \"Tie\"\n",
    "        return \"Bob\"\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        n = len(stoneValue)\n",
    "        sup = [0] * (n + 1)  # 后缀和\n",
    "        for i in range(n - 1, -1, -1):\n",
    "            sup[i] = sup[i + 1] + stoneValue[i]\n",
    "        @cache\n",
    "        def dfs(i):\n",
    "            if i == n: return 0\n",
    "            if i == n - 1: return stoneValue[i]\n",
    "            res = stoneValue[i] + (sup[i + 1] - dfs(i + 1))\n",
    "            if i < n - 1:\n",
    "                res = max(res, stoneValue[i] + stoneValue[i + 1] + (sup[i + 2] - dfs(i + 2)))\n",
    "            if i < n - 2:\n",
    "                res = max(res, stoneValue[i] + stoneValue[i + 1] + stoneValue[i + 2] + (sup[i + 3] - dfs(i + 3)))\n",
    "            return res\n",
    "        res = dfs(0)\n",
    "        if res * 2 > sup[0]:\n",
    "            return 'Alice'\n",
    "        elif res * 2 == sup[0]:\n",
    "            return 'Tie'\n",
    "        else:\n",
    "            return 'Bob'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import sys\n",
    "from functools import lru_cache\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: [int]) -> str:\n",
    "        piles=stoneValue\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def dfs(ll: int, rr: int):\n",
    "            if ll>rr: return 0\n",
    "            if ll==rr: return piles[ll]\n",
    "            tmp=-sys.maxsize\n",
    "            if rr>=ll:\n",
    "                tmp1 = piles[ll] - dfs(ll + 1, rr)\n",
    "                tmp=max(tmp,tmp1)\n",
    "            if rr-ll>=1:\n",
    "                tmp2 = piles[ll]+piles[ll+1]-dfs(ll+2, rr)\n",
    "                tmp = max(tmp, tmp2)\n",
    "            if rr-ll>=2:\n",
    "                tmp3 = piles[ll]+piles[ll+1]+piles[ll+2]-dfs(ll+3, rr)\n",
    "                tmp = max(tmp, tmp3)\n",
    "            return tmp\n",
    "\n",
    "        ans=dfs(0, len(piles) - 1)\n",
    "        if ans>0: return \"Alice\"\n",
    "        elif ans<0: return \"Bob\"\n",
    "        else: return \"Tie\"\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        s = sum(stoneValue)\n",
    "        s1 = s\n",
    "        score = [s]\n",
    "        for i in range(len(stoneValue)):\n",
    "            s -= stoneValue[i]\n",
    "            score.append(s)\n",
    "\n",
    "        @cache\n",
    "        def dfs(i):\n",
    "            if i == len(stoneValue):\n",
    "                return 0\n",
    "            ans = -inf\n",
    "            for j in range(i,min(i+3,len(stoneValue))):\n",
    "                ans = max(ans,score[i]-dfs(j+1))\n",
    "            return ans\n",
    "\n",
    "        alice = dfs(0)\n",
    "        bob = s1 - alice\n",
    "        if alice > bob:\n",
    "            return 'Alice'\n",
    "        elif alice < bob:\n",
    "            return 'Bob'\n",
    "        else:\n",
    "            return 'Tie'\n",
    "\n",
    "            \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def advantage(i, j):\n",
    "            if i>j: return 0\n",
    "            res = float(\"-inf\")\n",
    "            for x in range(1,4):\n",
    "                # i+x最大可以取到j+1\n",
    "                if i+x>j+1: continue\n",
    "                # res = max(res, sum(stoneValue[i:i+x])-advantage(i+x, j))\n",
    "                # 使用前缀和\n",
    "                res = max(res, presum[i+x-1]-presum[i-1]-advantage(i+x, j))\n",
    "            return res\n",
    "\n",
    "        # presum[-1]是为0服务的\n",
    "        presum = [0]*(len(stoneValue)+1)\n",
    "        pres = 0\n",
    "        for i, x in enumerate(stoneValue):\n",
    "            pres+=x\n",
    "            presum[i] = pres\n",
    "\n",
    "        res = advantage(0, len(stoneValue)-1)\n",
    "        if res>0: return \"Alice\"\n",
    "        elif res==0: return \"Tie\"\n",
    "        else: return \"Bob\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "\n",
    "        pres = list(accumulate(stoneValue, initial=0))\n",
    "        n = len(stoneValue)\n",
    "\n",
    "        @cache\n",
    "        def dfs(i, j):\n",
    "            if i > j:\n",
    "                return 0\n",
    "            res = -inf\n",
    "            for k in range(1, 4):\n",
    "                if i + k <= n:\n",
    "                    res = max(res, pres[i + k] - pres[i] - dfs(i + k, j))\n",
    "            return res\n",
    "        res = dfs(0, n - 1)\n",
    "        return 'Alice' if res > 0 else 'Tie' if res == 0 else 'Bob'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        @cache\n",
    "        def play(i):\n",
    "            if i == len(stoneValue):\n",
    "                return (0, 0)\n",
    "            \n",
    "            first = second = float('-inf')\n",
    "            for j in range(i, min(i + 3, len(stoneValue))):\n",
    "                next_first, next_second = play(j + 1)\n",
    "                if next_second + sum(stoneValue[i:j + 1]) > first:\n",
    "                    first = next_second + sum(stoneValue[i:j + 1])\n",
    "                    second = next_first\n",
    "            \n",
    "            return (first, second)\n",
    "\n",
    "        first, second = play(0)\n",
    "\n",
    "        if first > second:\n",
    "            return 'Alice'\n",
    "        elif first == second:\n",
    "            return 'Tie'\n",
    "        else:\n",
    "            return 'Bob'\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        n = len(stoneValue)\n",
    "        s = [stoneValue[-1]] * n\n",
    "        for i in range(n - 2, -1 , -1):\n",
    "            s[i] = s[i + 1] + stoneValue[i]\n",
    "\n",
    "        ans = [0] * (n+1)\n",
    "        X = [0] * n\n",
    "        # 回溯\n",
    "        @functools.lru_cache(None)\n",
    "        def helper(st):\n",
    "            if st >= n:\n",
    "                return 0\n",
    "            \n",
    "            max_score = -float(\"inf\")\n",
    "            t = st\n",
    "            for x in range(1, 3 + 1):\n",
    "        #        max_score = max(max_score, s[st] - helper(st+x))\n",
    "                \n",
    "                if max_score < s[st] - helper(st+x):\n",
    "                    max_score = s[st] - helper(st+x)\n",
    "                    t = st + x\n",
    "\n",
    "            ans[st] = max_score\n",
    "            X[st] = t\n",
    "            return max_score\n",
    "\n",
    "        helper(0)\n",
    "\n",
    "        if ans[0] > ans[X[0]]:\n",
    "            return \"Alice\"\n",
    "        elif ans[0] == ans[X[0]]:\n",
    "            return \"Tie\"\n",
    "        else:\n",
    "            return \"Bob\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, s: List[int]) -> str:\n",
    "        n=len(s)\n",
    "        pre=[0]+list(accumulate(s))\n",
    "        @cache\n",
    "        def dfs(l,r):\n",
    "            if l>r:return 0\n",
    "            if r==l:\n",
    "                return s[l]\n",
    "            ans=-inf\n",
    "            for i in range(3):\n",
    "                if l+i<=r:\n",
    "                    ans=max(ans,pre[l+i+1]-pre[l]-dfs(l+i+1,r))\n",
    "            \n",
    "            return ans\n",
    "        \n",
    "        res= dfs(0,n-1)\n",
    "        return \"Alice\" if res>0 else (\"Bob\" if res<0 else \"Tie\")\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        \n",
    "        presum = [0]\n",
    "        for i in stoneValue:\n",
    "            presum.append(presum[-1]+i)\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def dp(i,j):\n",
    "            ans = float(\"-inf\")\n",
    "            if i > j:\n",
    "                return 0\n",
    "            for k in range(3):\n",
    "                if i+k <= j:\n",
    "                    ans = max(ans, presum[j+1] - presum[i] - dp(i+k+1,j))\n",
    "            return ans\n",
    "        n = len(stoneValue)\n",
    "        ans = dp(0,n-1)\n",
    "        if presum[n] - ans < ans:\n",
    "            return \"Alice\"\n",
    "        elif  presum[n] - ans > ans:\n",
    "            return \"Bob\"\n",
    "        else:\n",
    "            return \"Tie\"\n",
    "        \n",
    "\n",
    "\n",
    "                    \n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        length = len(stoneValue)\n",
    "        memo = defaultdict()\n",
    "        sum_memo = defaultdict()\n",
    "        sum_memo[length - 1] = stoneValue[-1]\n",
    "        for i in range(length - 2, -1, -1):\n",
    "            sum_memo[i] = sum_memo[i + 1] + stoneValue[i]\n",
    "\n",
    "        def dfs(i):\n",
    "            if i in memo:\n",
    "                return memo[i]\n",
    "            if i == length - 1:\n",
    "                memo[i] = stoneValue[-1]\n",
    "                return stoneValue[-1]\n",
    "            if length <= i:\n",
    "                memo[i] = 0\n",
    "                return 0\n",
    "            for x in range(1, 4):\n",
    "                memo[i] = max(memo.get(i, float('-inf')), sum_memo[i] - dfs(i + x))\n",
    "            return memo[i]\n",
    "\n",
    "        dfs(0)\n",
    "        if sum(stoneValue) - memo[0] < memo[0]:\n",
    "            return \"Alice\"\n",
    "        elif sum(stoneValue) - memo[0] == memo[0]:\n",
    "            return \"Tie\"\n",
    "        else:\n",
    "            return \"Bob\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        # F[i] = S[i-1] - F[i-1], S[i-2] - F[i-2], S[i-3] - F[i-3]\n",
    "        nums = stoneValue[::-1]\n",
    "        S = []\n",
    "        s = 0\n",
    "        for n in nums:\n",
    "            s += n\n",
    "            S.append(s)\n",
    "            \n",
    "        from functools import lru_cache\n",
    "        \n",
    "        @lru_cache(100000)\n",
    "        def foo(i):\n",
    "            if i == -1:\n",
    "                return 0\n",
    "            elif i == 0:\n",
    "                return nums[0]\n",
    "            else:\n",
    "                inf = float('inf')\n",
    "                res = max(S[i]-foo(i-1), S[i]-foo(i-2) if i >= 1 else -inf, S[i]-foo(i-3) if i >= 2 else -inf)\n",
    "                # print(nums[:i+1], res, S[i])\n",
    "                return res \n",
    "        \n",
    "        r = foo(len(nums)-1)\n",
    "        o = S[-1] - r\n",
    "        \n",
    "        \n",
    "        if r == o:\n",
    "            return 'Tie'\n",
    "        elif r > o:\n",
    "            return 'Alice'\n",
    "        else:\n",
    "            return 'Bob'\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "    \tn=len(stoneValue)\n",
    "    \tpre=[0]*(n+1)\n",
    "    \tfor i in range(n):\n",
    "    \t\tpre[i+1]=pre[i]+stoneValue[i]\n",
    "\n",
    "    \tinf=float('-inf')\n",
    "    \t# 在[l,r]范围获得的最大石子数\n",
    "    \t@functools.lru_cache(None)\n",
    "    \tdef f(l,r):\n",
    "    \t\tif l>r:return 0\n",
    "    \t\tif l==r:return stoneValue[l]\n",
    "    \t\ttotal=pre[r+1]-pre[l]\n",
    "\n",
    "    \t\tres=inf\n",
    "    \t\tfor i in range(l,l+3):\n",
    "    \t\t\t# total=(pre[i+1]-pre[l])+(pre[r+1]-pre[i+1])\n",
    "    \t\t\tres=max(res, total-f(i+1,r))\n",
    "    \t\treturn res\n",
    "\n",
    "    \tfst=f(0,n-1)\n",
    "    \tif fst>pre[n]-fst:return 'Alice'\n",
    "    \telif fst<pre[n]-fst:return 'Bob'\n",
    "    \telse:return 'Tie'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        n = len(stoneValue)\n",
    "        for i in range(n-2, -1, -1):\n",
    "            stoneValue[i] += stoneValue[i+1]\n",
    "        self.stoneValue = stoneValue\n",
    "        # print(stoneValue)\n",
    "        alice = self.dfs(0)\n",
    "\n",
    "        # print(\"alice {}, bob {}\".format(alice, stoneValue[0] - alice))\n",
    "        if alice > stoneValue[0] - alice:\n",
    "            return \"Alice\"\n",
    "        elif alice < stoneValue[0] - alice:\n",
    "            return \"Bob\"\n",
    "        return \"Tie\"\n",
    "    \n",
    "    @cache\n",
    "    def dfs(self, start):\n",
    "        n = len(self.stoneValue)\n",
    "\n",
    "        if start >= n:\n",
    "            return 0\n",
    "        if start == n -1:\n",
    "            return self.stoneValue[start]\n",
    "        \n",
    "        return self.stoneValue[start] - min( self.dfs(i) for i in range(start+1, min(n+1,start+4)))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import functools, sys\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue) -> str:\n",
    "\n",
    "        @functools.lru_cache(None)\n",
    "        def helper(i):\n",
    "            if i >= len(stoneValue):\n",
    "                return 0\n",
    "            if i == len(stoneValue) - 1:\n",
    "                return stoneValue[-1]\n",
    "            ans = -sys.maxsize\n",
    "            total = _sum(i)\n",
    "            for x in range(3):\n",
    "                if i + x >= len(stoneValue): continue\n",
    "                ans = max(ans, total - helper(i + x + 1))\n",
    "            return ans\n",
    "        \n",
    "        @functools.lru_cache(None)\n",
    "        def _sum(i):\n",
    "            if i >= len(stoneValue): return 0\n",
    "            return stoneValue[i] + _sum(i+1)\n",
    "        \n",
    "        A = helper(0)\n",
    "        B = sum(stoneValue) - A\n",
    "        if A == B: return 'Tie'\n",
    "        if A > B: return 'Alice'\n",
    "        else: return 'Bob'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        l = len(stoneValue)\n",
    "        prefix = [0] * (l + 1)\n",
    "        for n in range(l):\n",
    "            prefix[n+1] = prefix[n] + stoneValue[n]\n",
    "\n",
    "        from functools import lru_cache\n",
    "        @lru_cache(None)\n",
    "        def dp(i, j, first):\n",
    "            if i == j:\n",
    "                return 0\n",
    "            if i == j - 1:\n",
    "                return stoneValue[i] if first else 0\n",
    "            max_val = float('-inf')\n",
    "            max_k = 0\n",
    "            for k in range(i + 1, min(i + 4, j + 1)):\n",
    "                curr = prefix[k] - prefix[i] + dp(k, j, False)\n",
    "                if curr > max_val:\n",
    "                    max_val = curr\n",
    "                    max_k = k\n",
    "            return max_val if first else dp(max_k, j, True)\n",
    "\n",
    "        first = dp(0, l, True)\n",
    "        second = dp(0, l, False)\n",
    "        if first > second:\n",
    "            return 'Alice'\n",
    "        elif first < second:\n",
    "            return 'Bob'\n",
    "        else:\n",
    "            return 'Tie'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import math\n",
    "from typing import List\n",
    "from functools import lru_cache\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def __init__(self):\n",
    "        self.s = None\n",
    "        self.sv = None\n",
    "        self.total = None\n",
    "        self.dp = None\n",
    "\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        \"\"\"\n",
    "        :param stoneValue:\n",
    "        :return:\n",
    "        \"\"\"\n",
    "        self.total = sum(stoneValue)\n",
    "        dp = {}\n",
    "        cache = 0\n",
    "        for k, v in enumerate(stoneValue):\n",
    "            cache += v\n",
    "            dp[k] = cache\n",
    "        dp[-1] = 0\n",
    "        self.dp = dp\n",
    "\n",
    "        self.s = len(stoneValue)\n",
    "        self.sv = stoneValue\n",
    "        maxscore = self.getN(0, )\n",
    "        if self.total % 2 != 0:\n",
    "            if maxscore * 2 > self.total:\n",
    "                return 'Alice'\n",
    "            return 'Bob'\n",
    "        else:\n",
    "            if maxscore > self.total // 2:\n",
    "                return 'Alice'\n",
    "            if maxscore < self.total // 2:\n",
    "                return 'Bob'\n",
    "            return 'Tie'\n",
    "\n",
    "    @lru_cache(None)\n",
    "    def getN(self, idx, ):\n",
    "        if idx == self.s:\n",
    "            return 0\n",
    "        if idx == self.s - 1:\n",
    "            return self.sv[idx]\n",
    "        if idx == self.s - 2:\n",
    "            if self.sv[idx] >= 0 and self.sv[idx + 1] >= 0:\n",
    "                return self.sv[idx] + self.sv[idx + 1]\n",
    "            if self.sv[idx] >= 0 >= self.sv[idx + 1]:\n",
    "                return self.sv[idx]\n",
    "            if self.sv[idx] < 0 < self.sv[idx + 1]:\n",
    "                return self.sv[idx] + self.sv[idx + 1]\n",
    "            if self.sv[idx] < 0 and self.sv[idx + 1] < 0:\n",
    "                return self.sv[idx]\n",
    "\n",
    "        maxV = -math.inf\n",
    "\n",
    "        for i in range(3):\n",
    "            idx1 = idx + i\n",
    "            if idx1 >= self.s:\n",
    "                break\n",
    "            sum1 = 0\n",
    "            for x in range(idx, idx + i + 1):\n",
    "                sum1 += self.sv[x]\n",
    "            val1 = sum1 + self.total - self.dp[idx1] - self.getN(idx1 + 1, )\n",
    "            maxV = max(maxV, val1)\n",
    "\n",
    "        return maxV\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        n = len(stoneValue)\n",
    "\n",
    "        sumstone = [0] * n\n",
    "        sumstone[-1] = stoneValue[-1]\n",
    "        for i in range(n-2,-1,-1):\n",
    "            sumstone[i] = stoneValue[i] + sumstone[i+1]\n",
    "        \n",
    "        @cache\n",
    "        def first(i):\n",
    "            if i >= n-3:\n",
    "                if i == n-1:\n",
    "                    return stoneValue[i]\n",
    "                elif i == n-2:\n",
    "                    return max(sum(stoneValue[-2:]),stoneValue[-2])\n",
    "                elif i == n-3:\n",
    "                    return max(sum(stoneValue[-3:]),stoneValue[-3]+stoneValue[-2],stoneValue[-3]+last(n-2))\n",
    "            \n",
    "            return max(stoneValue[i]+last(i+1),stoneValue[i]+stoneValue[i+1]+last(i+2),stoneValue[i]+stoneValue[i+1]+stoneValue[i+2]+last(i+3))\n",
    "\n",
    "        @cache\n",
    "        def last(i):\n",
    "            return sumstone[i] - first(i)\n",
    "        \n",
    "        a = first(0)\n",
    "        b = last(0)\n",
    "\n",
    "        if a > b:\n",
    "            return 'Alice'\n",
    "        if a < b:\n",
    "            return 'Bob'\n",
    "        return 'Tie'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        inf = -(1 << 30)\n",
    "        dp = {}\n",
    "\n",
    "        def f(ab, x):\n",
    "            # max delta\n",
    "            if x >= len(stoneValue):\n",
    "                return 0\n",
    "            \n",
    "            if (ab, x) in dp:\n",
    "                return dp[(ab, x)]\n",
    "\n",
    "            v = 0\n",
    "            ans = inf\n",
    "            for i in range(3):\n",
    "                if (i+x) >= len(stoneValue):\n",
    "                    break\n",
    "\n",
    "                v += stoneValue[i+x]\n",
    "                res = f(1- ab, i+x+1)\n",
    "                ans = max(ans, v - res)\n",
    "        \n",
    "            dp[(ab,x)] = ans\n",
    "            return ans\n",
    "        \n",
    "        ans = f(0, 0)\n",
    "        # print(dp, ans)\n",
    "        if ans > 0:\n",
    "            ans = 'Alice'\n",
    "        elif ans < 0:\n",
    "            ans = 'Bob'\n",
    "        else:\n",
    "            ans = 'Tie'\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIII(self, stoneValue: List[int]) -> str:\n",
    "        n = len(stoneValue)\n",
    "        @cache\n",
    "        def dp(isA, sI):#return the net score? #a want max(sA - sB), b want max(sB-sA)\n",
    "            sA, sB = 0, 0\n",
    "            if sI == n: return 0\n",
    "            ret = -inf\n",
    "            for ni in range(sI, min(sI+3, n)):\n",
    "                if isA: sA+=stoneValue[ni]\n",
    "                else: sB+= stoneValue[ni]\n",
    "                r = dp(not isA, ni+1)\n",
    "                if isA:\n",
    "                    ret = max(ret, (sA-r))\n",
    "                else:\n",
    "                    ret = max(ret, (sB-r))\n",
    "            return ret\n",
    "        r = dp(True, 0)\n",
    "        # print(r)\n",
    "        if r > 0: return 'Alice'\n",
    "        if r < 0: return 'Bob'\n",
    "        return 'Tie'\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        # 1 1 2 1 2 1 2 1 2 ...\n",
    "        # 2 2 1 2 1 2 1 2 1 ...\n",
    "        cnts = [0] * 3\n",
    "        for num in stones:\n",
    "            if not (m := num % 3):\n",
    "                cnts[m] ^= 1\n",
    "            else:\n",
    "                cnts[m] += 1\n",
    "        if not cnts[0]:\n",
    "            # Alice获胜的策略必然是先取1或2中更少的那个，如果有一个没得可取，\n",
    "            # 那么Alice必然是拿到第一个模3余0（第三次为Alice取），要么石子全拿光也不会是0（比如两个1）\n",
    "            return min(cnts[1], cnts[2]) > 0\n",
    "        else:\n",
    "            # 拥有了一个先手反制的选择（再非第一回合选择模3余0的数，会导致本来该自己必须选某堆石子变为对方必须先选）\n",
    "            # 那么Alice第一回合必须拿更多的那边的石子（更少会导致对方拿模3余0，我们面对上面分析的必输态）\n",
    "            # 如果拿走一个以后，更多的石子和另一堆一样多 或者 只多一个，那么Bob总有永远和不为3且取光所有石子的选择。\n",
    "            return abs(cnts[1] - cnts[2]) > 2\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        cnt = [0] * 3\n",
    "        for v in stones:\n",
    "            cnt[v % 3] += 1\n",
    "        if cnt[0] % 2 == 0 and cnt[1] * cnt[2] > 0:\n",
    "            return True\n",
    "        if cnt[0] % 2 == 1 and abs(cnt[1] - cnt[2]) >= 3:\n",
    "            return True\n",
    "        return False\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        cnt0 = cnt1 = cnt2 = 0\n",
    "        for val in stones:\n",
    "            if (typ := val % 3) == 0:\n",
    "                cnt0 += 1\n",
    "            elif typ == 1:\n",
    "                cnt1 += 1\n",
    "            else:\n",
    "                cnt2 += 1\n",
    "        if cnt0 % 2 == 0:\n",
    "            return cnt1 >= 1 and cnt2 >= 1\n",
    "        return cnt1 - cnt2 > 2 or cnt2 - cnt1 > 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        cnt = [0] * 3\n",
    "        for v in stones:\n",
    "            cnt[v % 3] += 1\n",
    "        if cnt[0] % 2 == 0 and cnt[1] * cnt[2] > 0:\n",
    "            return True\n",
    "        if cnt[0] % 2 == 1 and abs(cnt[1] - cnt[2]) >= 3:\n",
    "            return True\n",
    "        return False\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        b = [0] * 3\n",
    "        for s in stones:\n",
    "            b[s % 3] += 1\n",
    "\n",
    "        def check(i):\n",
    "            a = deepcopy(b)\n",
    "            a[i] -= 1\n",
    "            cnt = i\n",
    "            n = len(stones) - 1\n",
    "            turn = 1\n",
    "            while n > 0:\n",
    "                if a[0] > 0:\n",
    "                    a[0] -= 1\n",
    "                elif a[cnt] > 0:\n",
    "                    a[cnt] -= 1\n",
    "                    cnt = 3 - cnt\n",
    "                else:\n",
    "                    return bool(turn)\n",
    "                n -= 1\n",
    "                turn = 1 - turn\n",
    "            return False\n",
    "        \n",
    "        if b[1] > 0 and check(1): return True\n",
    "        if b[2] > 0 and check(2): return True\n",
    "        return False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        s = [0,0,0]\n",
    "        for i in stones:\n",
    "            s[i % 3] += 1\n",
    "        if s[1] * s[2] > 0 and s[0] % 2 == 0:\n",
    "            return True\n",
    "        elif abs(s[1] - s[2]) >= 3 and s[0]%2 == 1:\n",
    "            return True\n",
    "        return False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        count=[0,0,0]\n",
    "        for stone in stones:\n",
    "            count[stone%3]+=1\n",
    "        if (count[1]==0 and count[2]<3) or (count[1]<3 and count[2]==0):\n",
    "            return False\n",
    "        if count[1]==0 or count[2]==0:\n",
    "            return (count[0]&1)!=0\n",
    "        if (count[0]&1)==0:\n",
    "            return True\n",
    "        return abs(count[1]-count[2])>2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        counts = [0, 0, 0]\n",
    "        for stone in stones:\n",
    "            counts[stone % 3] += 1\n",
    "        if counts[0] % 2 == 0:\n",
    "            return counts[1] >= 1 and counts[2] >= 1\n",
    "        else:\n",
    "            return abs(counts[1] - counts[2]) > 2\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        zero = one = two = 0\n",
    "        for stone in stones:\n",
    "            if stone % 3 == 0:\n",
    "                zero += 1\n",
    "            elif stone % 3 == 1:\n",
    "                one += 1\n",
    "            else:\n",
    "                two += 1\n",
    "\n",
    "        ma, mi = one, two\n",
    "        if ma < mi:\n",
    "            ma, mi = mi, ma\n",
    "        \n",
    "        if mi == 0:\n",
    "            return ma > 2 and zero % 2 == 1\n",
    "        \n",
    "        if zero % 2 == 0:\n",
    "            return True\n",
    "\n",
    "        return ma - mi > 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        count = [0, 0, 0]\n",
    "        for stone in stones:\n",
    "            count[stone % 3] += 1\n",
    "\n",
    "        if count[1] == 0 and count[2] == 0:\n",
    "            return False\n",
    "        if count[0] % 2 == 0:\n",
    "            return count[1] > 0 and count[2] > 0\n",
    "        else:\n",
    "            return abs(count[1] - count[2]) > 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        cnt = [0,0,0]\n",
    "        for v in stones: cnt[v%3] += 1\n",
    "        if cnt[0]%2==0:return cnt[1] >=1 and cnt[2]>=1\n",
    "        return abs(cnt[1]-cnt[2])>2\n",
    "\n",
    "        \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        n = len(stones)\n",
    "        if n == 1: return False\n",
    "        \n",
    "        def check(first, mod):\n",
    "            if mod[first] > 0:\n",
    "                mod[first] -= 1\n",
    "                state = first\n",
    "                while True:\n",
    "                    # bob\n",
    "                    if mod[state] > 0: \n",
    "                        mod[state] -= 1\n",
    "                        state = 3 - state\n",
    "                    elif mod[0] > 0:\n",
    "                        mod[0] -= 1\n",
    "                    else:\n",
    "                        return True\n",
    "                    \n",
    "                    if mod[0] + mod[1] + mod[2] == 0:\n",
    "                        return False\n",
    "                    \n",
    "                    # alice\n",
    "                    if mod[state] > 0: \n",
    "                        mod[state] -= 1\n",
    "                        state = 3 - state\n",
    "                    elif mod[0] > 0:\n",
    "                        mod[0] -= 1\n",
    "                    else:\n",
    "                        return False\n",
    "                    \n",
    "                    if mod[0] + mod[1] + mod[2] == 0:\n",
    "                        return False\n",
    "            \n",
    "            return False\n",
    "        \n",
    "        mods = [0, 0, 0]\n",
    "        for i in range(n):\n",
    "            mods[stones[i] % 3] += 1\n",
    "            \n",
    "        # alice第一步只能取1或者2\n",
    "        return check(1, mods[:]) or check(2, mods[:])\n",
    "        \n",
    "        \n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        arr = [0,0,0]\n",
    "        for s in stones:\n",
    "            arr[s%3]+=1\n",
    "\n",
    "        def f(cnt):\n",
    "            if cnt[1]==0:\n",
    "                return False\n",
    "            cnt[1]-=1\n",
    "            turns = 1 + cnt[0] + min(cnt[1],cnt[2])*2\n",
    "            \n",
    "            if cnt[1] > cnt[2]:\n",
    "                turns += 1\n",
    "                cnt[1] -=1\n",
    "        \n",
    "            return turns % 2 == 1 and cnt[1] != cnt[2]\n",
    "        return f(arr.copy()) or f([arr[0],arr[2],arr[1]])\n",
    "                \n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        n = len(stones)\n",
    "        rec = [0]*3\n",
    "        for s in stones:\n",
    "            rec[s%3]+=1\n",
    "        res = False\n",
    "        #先拿1\n",
    "        s0,s1,s2 = rec[0],rec[1],rec[2]\n",
    "        if s1>0:\n",
    "            cot = 1+2*min(s1-1, s2)+s0+(1 if s1-1>s2 else 0)\n",
    "            if cot%2==1 and cot<n:\n",
    "                res = True\n",
    "        if s2>0:\n",
    "            cot = 1+2*min(s1, s2-1)+s0+(1 if s2-1>s1 else 0)\n",
    "            if cot%2==1 and cot<n:\n",
    "                res = True\n",
    "        #先拿2\n",
    "        return res\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from typing import List\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        cnts = [0] * 3\n",
    "        for num in stones:\n",
    "            if not (m := num % 3):\n",
    "                cnts[m] ^= 1\n",
    "            else:\n",
    "                cnts[m] += 1\n",
    "        if not cnts[0]:\n",
    "            return min(cnts[1], cnts[2]) > 0\n",
    "        else:\n",
    "            return abs(cnts[1] - cnts[2]) > 2\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        cnt = [0] * 3\n",
    "        for i in stones:\n",
    "            cnt[i % 3] += 1\n",
    "        if cnt[0] % 2 == 0 and cnt[1] * cnt[2] > 0:\n",
    "            return True\n",
    "        if cnt[0] % 2 == 1 and abs(cnt[1] - cnt[2]) >= 3:\n",
    "            return True\n",
    "        return False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        # 随机移除一个数字 将某个局面留给你\n",
    "        # 最后的结果就是剩下1 还是剩下2\n",
    "        def check(c):\n",
    "            # 第一回合选择1 还是选择2\n",
    "            al = sum(c)\n",
    "            if c[1] == 0:\n",
    "                return False\n",
    "            c[1] -= 1\n",
    "            # 交替选择1或者2\n",
    "            turn = 1 + min(c[1], c[2]) * 2 + c[0]\n",
    "            if c[1] > c[2]:\n",
    "                turn += 1\n",
    "                c[1] -= 1\n",
    "            return turn % 2 == 1 and turn != al\n",
    "        cnt = [0, 0, 0]\n",
    "        for i in stones:\n",
    "            cnt[i%3] += 1\n",
    "        # alice第一次先手选择1 还是先手选择2\n",
    "        # 1 2 指的是使得和余数为1 还是2 的办法 有一种能让alice赢即可\n",
    "        return check(cnt.copy()) or check([cnt[0], cnt[2], cnt[1]])\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        n = len(stones)\n",
    "        rec = [0]*3\n",
    "        for s in stones:\n",
    "            rec[s%3]+=1\n",
    "        res = False\n",
    "        #先拿1\n",
    "        s0,s1,s2 = rec[0],rec[1],rec[2]\n",
    "        if s1>0:\n",
    "            cot = 1+2*min(s1-1, s2)+s0+(1 if s1-1>s2 else 0)\n",
    "            if cot%2==1 and cot<n:\n",
    "                res = True\n",
    "        #先拿2\n",
    "        if s2>0:\n",
    "            cot = 1+2*min(s1, s2-1)+s0+(1 if s2-1>s1 else 0)\n",
    "            if cot%2==1 and cot<n:\n",
    "                res = True\n",
    "        return res\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        def check(c:List[int]):\n",
    "            if c[1]==0:\n",
    "                return False\n",
    "            c[1]-=1\n",
    "            turn=1+min(c[1],c[2])*2+c[0]\n",
    "            if c[1]>c[2]:\n",
    "                turn+=1\n",
    "                c[1]-=1\n",
    "            return turn%2==1 and c[1]!=c[2]\n",
    "        c=[0]*3\n",
    "        for stone in stones:\n",
    "            c[stone%3]+=1\n",
    "        c1=[c[0],c[2],c[1]]\n",
    "        return check(c) or check(c1)\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        # 分类构造，cnt0/cnt1/cnt2 分别表示石子值%3=0/1/2的个数\n",
    "        cnt0 = cnt1 = cnt2 = 0\n",
    "        for val in stones:\n",
    "            if (typ := val % 3) == 0:\n",
    "                cnt0 += 1\n",
    "            elif typ == 1:\n",
    "                cnt1 += 1\n",
    "            else:\n",
    "                cnt2 += 1\n",
    "        if cnt0 % 2 == 0:\n",
    "            return cnt1 >= 1 and cnt2 >= 1\n",
    "        return cnt1 - cnt2 > 2 or cnt2 - cnt1 > 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from typing import List\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        cnts = [0] * 3\n",
    "        for num in stones:\n",
    "            if not (m := num % 3):\n",
    "                cnts[m] ^= 1\n",
    "            else:\n",
    "                cnts[m] += 1\n",
    "        if not cnts[0]:\n",
    "            return min(cnts[1], cnts[2]) > 0\n",
    "        else:\n",
    "            return abs(cnts[1] - cnts[2]) > 2\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        cnt = Counter()\n",
    "        for s in stones:\n",
    "            cnt[s % 3] += 1\n",
    "        \n",
    "        a, b, c = cnt[1], cnt[2], cnt[0]\n",
    "\n",
    "        if c % 2 == 0:\n",
    "            if a == 0 or b == 0:\n",
    "                return False\n",
    "        else:\n",
    "            if abs(a - b) <= 2:\n",
    "                return False\n",
    "\n",
    "        return True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        # 随机移除一个数字 将某个局面留给你\n",
    "        # 最后的结果就是剩下1 还是剩下2\n",
    "        def check(c):\n",
    "            # 第一回合选择1 还是选择2\n",
    "            if c[1] == 0:\n",
    "                return False\n",
    "            c[1] -= 1\n",
    "            # 交替选择1或者2\n",
    "            turn = 1 + min(c[1], c[2]) * 2 + c[0]\n",
    "            if c[1] > c[2]:\n",
    "                turn += 1\n",
    "                c[1] -= 1\n",
    "            return turn % 2 == 1 and c[1] != c[2]\n",
    "        cnt = [0, 0, 0]\n",
    "        for i in stones:\n",
    "            cnt[i%3] += 1\n",
    "        # alice第一次先手选择1 还是先手选择2\n",
    "        # 1 2 指的是使得和余数为1 还是2 的办法 有一种能让alice赢即可\n",
    "        return check(cnt.copy()) or check([cnt[0], cnt[2], cnt[1]])\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        # 随机移除一个数字 将某个局面留给你\n",
    "        # 最后的结果就是剩下1 还是剩下2\n",
    "        al = len(stones)\n",
    "        def check(c):\n",
    "            # 第一回合选择1 还是选择2\n",
    "            if c[1] == 0:\n",
    "                return False\n",
    "            c[1] -= 1\n",
    "            # 交替选择1或者2\n",
    "            turn = 1 + min(c[1], c[2]) * 2 + c[0]\n",
    "            if c[1] > c[2]:\n",
    "                turn += 1\n",
    "                c[1] -= 1\n",
    "            # 轮到bob选石头 而且还有剩余石头 这个时候剩下的石头肯定是使得和的余数是3的\n",
    "            return turn % 2 == 1 and turn != al\n",
    "        cnt = [0, 0, 0]\n",
    "        for i in stones:\n",
    "            cnt[i%3] += 1\n",
    "        # alice第一次先手选择1 还是先手选择2\n",
    "        # 1 2 指的是使得和余数为1 还是2 的办法 有一种能让alice赢即可\n",
    "        return check(cnt.copy()) or check([cnt[0], cnt[2], cnt[1]])\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        stones = [x % 3 for x in stones]\n",
    "        n = len(stones)\n",
    "        counter = Counter(stones)\n",
    "        if counter[1] == counter[2] == 0:\n",
    "            return False\n",
    "        if counter[1] == 0:\n",
    "            # 2 最多用两次，其他都用 0\n",
    "            t = min(2, counter[2]) + counter[0]\n",
    "            return True if t & 1 and t != n else False\n",
    "        if counter[2] == 0:\n",
    "            # 1 最多用两次，其他都用 0\n",
    "            t = min(2, counter[1]) + counter[0]\n",
    "            return True if t & 1 and t != n else False\n",
    "        # 先走1\n",
    "        x1 = min(counter[1] - 1, counter[2])\n",
    "        t1 = 1 + x1 * 2 + (counter[1] - 1 > x1) + counter[0]  # 一共能走的步数\n",
    "        # 先走2\n",
    "        x2 = min(counter[2] - 1, counter[1])\n",
    "        t2 = 1 + x2 * 2 + (counter[2] - 1 > x2) + counter[0]  # 一共能走的步数\n",
    "        if (t1 & 1 and t1 != n) or (t2 & 1 and t2 != n):\n",
    "            return True\n",
    "        return False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        cnt = Counter([x%3 for x in stones])\n",
    "        return abs(cnt[1]-cnt[2])>2 if cnt[0] & 1 else min(cnt[1],cnt[2])>0\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        cnt = Counter([x%3 for x in stones])\n",
    "        return abs(cnt[1]-cnt[2])>2 if cnt[0] & 1 else min(cnt[1],cnt[2])>0\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        cnt = Counter([x%3 for x in stones])\n",
    "        return abs(cnt[1]-cnt[2])>2 if cnt[0] & 1 else min(cnt[1],cnt[2])>0\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        cnt = Counter([x%3 for x in stones])\n",
    "        return abs(cnt[1]-cnt[2])>2 if cnt[0] & 1 else min(cnt[1],cnt[2])>0\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameIX(self, stones: List[int]) -> bool:\n",
    "        stones = [stone % 3 for stone in stones]\n",
    "        cnts = Counter(stones)\n",
    "\n",
    "        def dfs(cnts,x,i):\n",
    "            if x == 1:\n",
    "                if cnts[1] > 0:\n",
    "                    cnts[1] -= 1\n",
    "                    if dfs(cnts,2,(i+1)%2):\n",
    "                        return True\n",
    "                    cnts[1] += 1\n",
    "                if cnts[0] % 2 == 0:\n",
    "                    return True if cnts[2] != 0 and cnts[1] == 0 and i % 2 == 1 else False\n",
    "                return True if cnts[2] != 0 and cnts[1] == 0 and i % 2 == 0 else False\n",
    "            elif x == 2:\n",
    "                if cnts[2] > 0:\n",
    "                    cnts[2] -= 1\n",
    "                    if dfs(cnts,1,(i+1)%2):\n",
    "                        return True\n",
    "                    cnts[2] += 1\n",
    "                if cnts[0] % 2 == 0:\n",
    "                    return True if cnts[1] != 0 and cnts[2] == 0 and i % 2 == 1 else False\n",
    "                return True if cnts[1] != 0 and cnts[2] == 0 and i % 2 == 0 else False\n",
    "            else:\n",
    "                if cnts[1] > 0:\n",
    "                    cnts[1] -= 1\n",
    "                    if dfs(cnts,1,(i+1)%2):\n",
    "                        return True\n",
    "                    cnts[1] += 1\n",
    "                if cnts[2] > 0:\n",
    "                    cnts[2] -= 1\n",
    "                    if dfs(cnts,2,(i+1)%2):\n",
    "                        return True\n",
    "                    cnts[2] += 1\n",
    "                return True if cnts[0] > 0 and cnts[1] == 0 and cnts[2] == 0 and i % 2 == 1 else False\n",
    "\n",
    "        return dfs(cnts,0,0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        f = [[0] * n for _ in range(n)]\n",
    "        maxl = [[0] * n for _ in range(n)]\n",
    "        maxr = [[0] * n for _ in range(n)]\n",
    "\n",
    "        for left in range(n - 1, -1, -1):\n",
    "            maxl[left][left] = maxr[left][left] = stoneValue[left]\n",
    "            total = stoneValue[left]\n",
    "            suml = 0\n",
    "            i = left - 1\n",
    "            for right in range(left + 1, n):\n",
    "                total += stoneValue[right]\n",
    "                while i + 1 < right and (suml + stoneValue[i + 1]) * 2 <= total:\n",
    "                    suml += stoneValue[i + 1]\n",
    "                    i += 1\n",
    "                if left <= i:\n",
    "                    f[left][right] = max(f[left][right], maxl[left][i])\n",
    "                if i + 1 < right:\n",
    "                    f[left][right] = max(f[left][right], maxr[i + 2][right])\n",
    "                if suml * 2 == total:\n",
    "                    f[left][right] = max(f[left][right], maxr[i + 1][right])\n",
    "                maxl[left][right] = max(maxl[left][right - 1], total + f[left][right])\n",
    "                maxr[left][right] = max(maxr[left + 1][right], total + f[left][right])\n",
    "        \n",
    "        return f[0][n - 1]\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        f = [[0] * n for _ in range(n)]\n",
    "        maxl = [[0] * n for _ in range(n)]\n",
    "        maxr = [[0] * n for _ in range(n)]\n",
    "\n",
    "        for left in range(n - 1, -1, -1):\n",
    "            maxl[left][left] = maxr[left][left] = stoneValue[left]\n",
    "            total = stoneValue[left]\n",
    "            suml = 0\n",
    "            i = left - 1\n",
    "            for right in range(left + 1, n):\n",
    "                total += stoneValue[right]\n",
    "                while i + 1 < right and (suml + stoneValue[i + 1]) * 2 <= total:\n",
    "                    suml += stoneValue[i + 1]\n",
    "                    i += 1\n",
    "                if left <= i:\n",
    "                    f[left][right] = max(f[left][right], maxl[left][i])\n",
    "                if i + 1 < right:\n",
    "                    f[left][right] = max(f[left][right], maxr[i + 2][right])\n",
    "                if suml * 2 == total:\n",
    "                    f[left][right] = max(f[left][right], maxr[i + 1][right])\n",
    "                maxl[left][right] = max(maxl[left][right - 1], total + f[left][right])\n",
    "                maxr[left][right] = max(maxr[left + 1][right], total + f[left][right])\n",
    "        \n",
    "        return f[0][n - 1]\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        f = [[0] * n for _ in range(n)]\n",
    "        maxl = [[0] * n for _ in range(n)]\n",
    "        maxr = [[0] * n for _ in range(n)]\n",
    "\n",
    "        for left in range(n - 1, -1, -1):\n",
    "            maxl[left][left] = maxr[left][left] = stoneValue[left]\n",
    "            total = stoneValue[left]\n",
    "            suml = 0\n",
    "            i = left - 1\n",
    "            for right in range(left + 1, n):\n",
    "                total += stoneValue[right]\n",
    "                while i + 1 < right and (suml + stoneValue[i + 1]) * 2 <= total:\n",
    "                    suml += stoneValue[i + 1]\n",
    "                    i += 1\n",
    "                if left <= i:\n",
    "                    f[left][right] = max(f[left][right], maxl[left][i])\n",
    "                if i + 1 < right:\n",
    "                    f[left][right] = max(f[left][right], maxr[i + 2][right])\n",
    "                if suml * 2 == total:\n",
    "                    f[left][right] = max(f[left][right], maxr[i + 1][right])\n",
    "                maxl[left][right] = max(maxl[left][right - 1], total + f[left][right])\n",
    "                maxr[left][right] = max(maxr[left + 1][right], total + f[left][right])\n",
    "        \n",
    "        return f[0][n - 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        s, maxl, maxr = [[0] * n for _ in range(n)], [[0] * n for _ in range(n)], [[0] * n for _ in range(n)]\n",
    "        for l in range(n - 1, -1, -1):\n",
    "            maxl[l][l] = maxr[l][l] = stoneValue[l]\n",
    "            total = stoneValue[l]\n",
    "            suml = 0\n",
    "            i = l - 1\n",
    "            for r in range(l + 1, n):\n",
    "                total += stoneValue[r]\n",
    "                while i + 1 < r and (suml + stoneValue[i + 1]) * 2 <= total:\n",
    "                    suml += stoneValue[i + 1]\n",
    "                    i += 1\n",
    "                if l <= i:\n",
    "                    s[l][r] = max(s[l][r], maxl[l][i])\n",
    "                if i + 1 < r:\n",
    "                    s[l][r] = max(s[l][r], maxr[i + 2][r])\n",
    "                if suml * 2 == total:\n",
    "                    s[l][r] = max(s[l][r], maxr[i + 1][r])\n",
    "                maxl[l][r] = max(maxl[l][r - 1], total + s[l][r])\n",
    "                maxr[l][r] = max(maxr[l + 1][r], total + s[l][r])\n",
    "        return s[0][n - 1]\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        f = [[0] * n for _ in range(n)]\n",
    "        maxl = [[0] * n for _ in range(n)]\n",
    "        maxr = [[0] * n for _ in range(n)]\n",
    "\n",
    "        for left in range(n - 1, -1, -1):\n",
    "            maxl[left][left] = maxr[left][left] = stoneValue[left]\n",
    "            total = stoneValue[left]\n",
    "            suml = 0\n",
    "            i = left - 1\n",
    "            for right in range(left + 1, n):\n",
    "                total += stoneValue[right]\n",
    "                while i + 1 < right and (suml + stoneValue[i + 1]) * 2 <= total:\n",
    "                    suml += stoneValue[i + 1]\n",
    "                    i += 1\n",
    "                if left <= i:\n",
    "                    f[left][right] = max(f[left][right], maxl[left][i])\n",
    "                if i + 1 < right:\n",
    "                    f[left][right] = max(f[left][right], maxr[i + 2][right])\n",
    "                if suml * 2 == total:\n",
    "                    f[left][right] = max(f[left][right], maxr[i + 1][right])\n",
    "                maxl[left][right] = max(maxl[left][right - 1], total + f[left][right])\n",
    "                maxr[left][right] = max(maxr[left + 1][right], total + f[left][right])\n",
    "        \n",
    "        return f[0][n - 1]\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        f = [[0] * n for _ in range(n)]\n",
    "        maxl = [[0] * n for _ in range(n)]\n",
    "        maxr = [[0] * n for _ in range(n)]\n",
    "\n",
    "        for left in range(n - 1, -1, -1):\n",
    "            maxl[left][left] = maxr[left][left] = stoneValue[left]\n",
    "            total = stoneValue[left]\n",
    "            suml = 0\n",
    "            i = left - 1\n",
    "            for right in range(left + 1, n):\n",
    "                total += stoneValue[right]\n",
    "                while i + 1 < right and (suml + stoneValue[i + 1]) * 2 <= total:\n",
    "                    suml += stoneValue[i + 1]\n",
    "                    i += 1\n",
    "                if left <= i:\n",
    "                    f[left][right] = max(f[left][right], maxl[left][i])\n",
    "                if i + 1 < right:\n",
    "                    f[left][right] = max(f[left][right], maxr[i + 2][right])\n",
    "                if suml * 2 == total:\n",
    "                    f[left][right] = max(f[left][right], maxr[i + 1][right])\n",
    "                maxl[left][right] = max(maxl[left][right - 1], total + f[left][right])\n",
    "                maxr[left][right] = max(maxr[left + 1][right], total + f[left][right])\n",
    "        \n",
    "        return f[0][n - 1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        f = [[0] * n for _ in range(n)]\n",
    "        maxl = [[0] * n for _ in range(n)]\n",
    "        maxr = [[0] * n for _ in range(n)]\n",
    "\n",
    "        for left in range(n - 1, -1, -1):\n",
    "            maxl[left][left] = maxr[left][left] = stoneValue[left]\n",
    "            total = stoneValue[left]\n",
    "            suml = 0\n",
    "            i = left - 1\n",
    "            for right in range(left + 1, n):\n",
    "                total += stoneValue[right]\n",
    "                while i + 1 < right and (suml + stoneValue[i + 1]) * 2 <= total:\n",
    "                    suml += stoneValue[i + 1]\n",
    "                    i += 1\n",
    "                if left <= i:\n",
    "                    f[left][right] = max(f[left][right], maxl[left][i])\n",
    "                if i + 1 < right:\n",
    "                    f[left][right] = max(f[left][right], maxr[i + 2][right])\n",
    "                if suml * 2 == total:\n",
    "                    f[left][right] = max(f[left][right], maxr[i + 1][right])\n",
    "                maxl[left][right] = max(maxl[left][right - 1], total + f[left][right])\n",
    "                maxr[left][right] = max(maxr[left + 1][right], total + f[left][right])\n",
    "        \n",
    "        return f[0][n - 1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        f = [[0] * n for _ in range(n)]\n",
    "        maxl = [[0] * n for _ in range(n)]\n",
    "        maxr = [[0] * n for _ in range(n)]\n",
    "\n",
    "        for left in range(n - 1, -1, -1):\n",
    "            maxl[left][left] = maxr[left][left] = stoneValue[left]\n",
    "            total = stoneValue[left]\n",
    "            suml = 0\n",
    "            i = left - 1\n",
    "            for right in range(left + 1, n):\n",
    "                total += stoneValue[right]\n",
    "                \n",
    "                while i + 1 < right and (suml + stoneValue[i + 1]) * 2 <= total:\n",
    "                    suml += stoneValue[i + 1]\n",
    "                    i += 1\n",
    "                if left <= i:\n",
    "                    f[left][right] = max(f[left][right], maxl[left][i])\n",
    "                if i + 1 < right:\n",
    "                    f[left][right] = max(f[left][right], maxr[i + 2][right])\n",
    "                if suml * 2 == total:\n",
    "                    f[left][right] = max(f[left][right], maxr[i + 1][right])\n",
    "                maxl[left][right] = max(maxl[left][right - 1], total + f[left][right])\n",
    "                maxr[left][right] = max(maxr[left + 1][right], total + f[left][right])\n",
    "        return f[0][n - 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        memo = [[0]*n for _ in range(n)]\n",
    "        maxLeft = [[0]*n for _ in range(n)]\n",
    "        maxRight = [[0]*n for _ in range(n)]\n",
    "        accum = [0]\n",
    "        for v in stoneValue:\n",
    "            accum.append(accum[-1]+v)\n",
    "\n",
    "        for left in range(n-1, -1, -1):\n",
    "            maxLeft[left][left] = maxRight[left][left] = stoneValue[left]\n",
    "            sumVal = stoneValue[left]\n",
    "            leftSumVal = 0\n",
    "            mid = left-1\n",
    "            for right in range(left+1, n):\n",
    "                sumVal += stoneValue[right]\n",
    "                while mid+1 < right and (leftSumVal+stoneValue[mid+1])*2 <= sumVal:\n",
    "                    leftSumVal += stoneValue[mid+1]\n",
    "                    mid += 1\n",
    "                if left <= mid:\n",
    "                    memo[left][right] = max(\n",
    "                        memo[left][right], maxLeft[left][mid])\n",
    "                if mid+1 < right:\n",
    "                    memo[left][right] = max(\n",
    "                        memo[left][right], maxRight[mid+2][right])\n",
    "                if leftSumVal*2 == sumVal:\n",
    "                    memo[left][right] = max(\n",
    "                        memo[left][right], maxRight[mid+1][right])\n",
    "                maxLeft[left][right] = max(\n",
    "                    maxLeft[left][right-1], sumVal+memo[left][right])\n",
    "                maxRight[left][right] = max(\n",
    "                    maxRight[left+1][right], sumVal+memo[left][right])\n",
    "        return memo[0][n-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        f = [[0] * n for _ in range(n)]\n",
    "        maxl, maxr = [[0] * n for _ in range(n)],[[0] * n for _ in range(n)]\n",
    "\n",
    "        for l in range(n-1,-1,-1):\n",
    "            maxl[l][l] = maxr[l][l] = stoneValue[l]\n",
    "            total = stoneValue[l]\n",
    "            suml = 0\n",
    "            i = l - 1\n",
    "\n",
    "            for r in range(l+1,n):\n",
    "                total += stoneValue[r]\n",
    "\n",
    "                while i + 1 < r and (suml + stoneValue[i+1]) * 2 <= total:\n",
    "                    suml += stoneValue[i+1]\n",
    "                    i += 1\n",
    "                \n",
    "                if l <= i:\n",
    "                    f[l][r] = max(f[l][r],maxl[l][i])\n",
    "                \n",
    "                if i + 1 < r:\n",
    "                    f[l][r] = max(f[l][r],maxr[i+2][r])\n",
    "                \n",
    "                if suml*2 == total:\n",
    "                    f[l][r] = max(f[l][r],maxr[i+1][r])\n",
    "                \n",
    "                maxl[l][r] = max(maxl[l][r-1], total + f[l][r])\n",
    "                maxr[l][r] = max(maxr[l+1][r], total + f[l][r])\n",
    "        \n",
    "        return f[0][n-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        f = [[0] * n for _ in range(n)]\n",
    "        maxl = [[0] * n for _ in range(n)]\n",
    "        maxr = [[0] * n for _ in range(n)]\n",
    "\n",
    "        for left in range(n - 1, -1, -1):\n",
    "            maxl[left][left] = maxr[left][left] = stoneValue[left]\n",
    "            total = stoneValue[left]\n",
    "            suml = 0\n",
    "            i = left - 1\n",
    "            for right in range(left + 1, n):\n",
    "                total += stoneValue[right]\n",
    "                \n",
    "                while i + 1 < right and (suml + stoneValue[i + 1]) * 2 <= total:\n",
    "                    suml += stoneValue[i + 1]\n",
    "                    i += 1\n",
    "                if left <= i:\n",
    "                    f[left][right] = max(f[left][right], maxl[left][i])\n",
    "                if i + 1 < right:\n",
    "                    f[left][right] = max(f[left][right], maxr[i + 2][right])\n",
    "                if suml * 2 == total:\n",
    "                    f[left][right] = max(f[left][right], maxr[i + 1][right])\n",
    "                maxl[left][right] = max(maxl[left][right - 1], total + f[left][right])\n",
    "                maxr[left][right] = max(maxr[left + 1][right], total + f[left][right])\n",
    "        return f[0][n - 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "        points = [[0] * n for _ in range(n)]\n",
    "        mxl = [[0] * n for _ in range(n)]\n",
    "        mxr = [[0] * n for _ in range(n)]\n",
    "        prefix = [0]\n",
    "\n",
    "        for i in range(n):\n",
    "            points[i][i] = i\n",
    "            mxl[i][i] = stoneValue[i]\n",
    "            mxr[i][i] = stoneValue[i]\n",
    "            prefix.append(prefix[-1] + stoneValue[i])\n",
    "        for i in range(n - 1):\n",
    "            for j in range(i + 1, n):\n",
    "                k = points[i][j - 1]\n",
    "                total = prefix[j + 1] - prefix[i]\n",
    "                while total - prefix[k + 1] + prefix[i] > prefix[k + 1] - prefix[i]:\n",
    "                    k += 1\n",
    "                points[i][j] = k\n",
    "                \n",
    "        for j in range(1, n):\n",
    "            for i in range(j - 1, -1, -1):\n",
    "                k = points[i][j]\n",
    "                left, right = prefix[k + 1] - prefix[i], prefix[j + 1] - prefix[k + 1]\n",
    "                if left == right:\n",
    "                    dp[i][j] = max(dp[i][j], mxl[i][k], mxr[k + 1][j])\n",
    "                else:\n",
    "                    if k > i:\n",
    "                        dp[i][j] = max(dp[i][j], mxl[i][k - 1])\n",
    "                    if k < j:\n",
    "                        dp[i][j] = max(dp[i][j], mxr[k + 1][j])\n",
    "                \n",
    "                mxl[i][j] = max(mxl[i][j - 1], dp[i][j] + prefix[j + 1] - prefix[i])\n",
    "                mxr[i][j] = max(mxr[i + 1][j], dp[i][j] + prefix[j + 1] - prefix[i])\n",
    "        \n",
    "        return dp[0][-1]\n",
    "\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    '''\n",
    "    区间DP + 博弈论DP\n",
    "    比较难理解，该写法是基于 https://leetcode.cn/problems/stone-game-v/submissions/467309295/ 的常规思路的优化\n",
    "    常规思路中递归两个入参组合的可能性为n * n，而递归内部又需要在两个入参内循环遍历所可能，又是一个n，因此最终的时间复杂度为\n",
    "    n^3，会超时，该优化方法就是将内部的区间遍历变成O(1)时间\n",
    "    基于如下的想法\n",
    "    在[i, j]的区间内一定存在一个k点，使得sum[i, k] 第一次大于等于 sum[k + 1, j]的，也可以用sum[i, k]最后一次小于等于sum[k + 1, j]，\n",
    "    具体使用哪个看个人习惯，这里用第一种定义，不同的k取值在代码的处理上有一定的差异（第二种处理方式可以参考官解）\n",
    "    由于数组都是正整数，所以当计算出[i, j]的特殊点k，当j变成j + 1时，我们只需要依赖k往后推导一次就能得到在[i, j + 1]区间上满足上述要求\n",
    "    的分割点k'，通过这种方式就可以将所有区间的分割点先算出来\n",
    "    \n",
    "    '''\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "        points = [[0] * n for _ in range(n)]\n",
    "        mxl = [[0] * n for _ in range(n)]\n",
    "        mxr = [[0] * n for _ in range(n)]\n",
    "        prefix = [0]\n",
    "\n",
    "        for i in range(n):\n",
    "            points[i][i] = i\n",
    "            mxl[i][i] = stoneValue[i]\n",
    "            mxr[i][i] = stoneValue[i]\n",
    "            prefix.append(prefix[-1] + stoneValue[i])\n",
    "        for i in range(n - 1):\n",
    "            for j in range(i + 1, n):\n",
    "                k = points[i][j - 1]\n",
    "                total = prefix[j + 1] - prefix[i]\n",
    "                '''\n",
    "                算第一个左边大于右边的点\n",
    "                '''\n",
    "                while total - prefix[k + 1] + prefix[i] > prefix[k + 1] - prefix[i]:\n",
    "                    k += 1\n",
    "                points[i][j] = k\n",
    "\n",
    "        '''\n",
    "        下面注释中的代码为什么不能替换注释下的代码，还没能理解（想了好几天没有想通），暂留疑问\n",
    "        '''\n",
    "        for j in range(1, n):\n",
    "            for i in range(j - 1, -1, -1):\n",
    "                k = points[i][j]\n",
    "                left, right = prefix[k + 1] - prefix[i], prefix[j + 1] - prefix[k + 1]\n",
    "                if left == right:\n",
    "                    # dp[i][j] = max(dp[i][j], dp[i][k], dp[k + 1][j])\n",
    "                    dp[i][j] = max(dp[i][j], mxl[i][k], mxr[k + 1][j])\n",
    "                else:\n",
    "                    '''\n",
    "                    因为上面的k其实是中间偏右的概念，因此可能k == i或者k == j，此时再用 k - 1或者\n",
    "                    k + 1就会有问题，比如[1, 3]，第一个左边大于右边的k = 1，此时k == j了，再判断\n",
    "                    k + 1就会溢出，所以这里要有两个判断\n",
    "                    '''\n",
    "                    if k > i:\n",
    "                        # dp[i][j] = max(dp[i][j], dp[i][k - 1] + prefix[k] - prefix[i])\n",
    "                        '''\n",
    "                        dp[i][k - 1]\n",
    "                        dp[i][p]\n",
    "                        '''\n",
    "                        dp[i][j] = max(dp[i][j], mxl[i][k - 1])\n",
    "                    if k < j:\n",
    "                        # dp[i][j] = max(dp[i][j], dp[k + 1][j] + prefix[j + 1] - prefix[k + 1])\n",
    "                        dp[i][j] = max(dp[i][j], mxr[k + 1][j])\n",
    "                \n",
    "                mxl[i][j] = max(mxl[i][j - 1], dp[i][j] + prefix[j + 1] - prefix[i])\n",
    "                mxr[i][j] = max(mxr[i + 1][j], dp[i][j] + prefix[j + 1] - prefix[i])\n",
    "        return dp[0][-1]\n",
    "\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        presum = [0]\n",
    "        middle = [[0 for _ in range(n)] for _ in range(n)]\n",
    "        leftMax = [[0 for _ in range(n)] for _ in range(n)]\n",
    "        rightMax = [[0 for _ in range(n)] for _ in range(n)]\n",
    "        dp = [[0 for _ in range(n)] for _ in range(n)]\n",
    "        for i, s in enumerate(stoneValue):\n",
    "            presum.append(presum[-1] + s)\n",
    "            middle[i][i] = i\n",
    "            leftMax[i][i] = stoneValue[i]\n",
    "            rightMax[i][i] = stoneValue[i]\n",
    "        for i in range(n):\n",
    "            for j in range(i + 1, n):\n",
    "                mid = middle[i][j - 1]\n",
    "                while mid < j and presum[j + 1] - presum[mid + 1] > presum[mid + 1] - presum[i]:\n",
    "                    mid += 1 \n",
    "                middle[i][j] = mid\n",
    "        for l in range(2, n + 1):\n",
    "            for i in range(n - l + 1):\n",
    "                j = i + l - 1 \n",
    "                mid = middle[i][j]\n",
    "                if i < mid:\n",
    "                    dp[i][j] = max(leftMax[i][mid - 1] , dp[i][j])\n",
    "                if j > mid:\n",
    "                    dp[i][j] = max(rightMax[mid + 1][j], dp[i][j])\n",
    "                if presum[j + 1] - presum[mid + 1] == presum[mid + 1] - presum[i]:\n",
    "                    dp[i][j] = max(dp[i][j], leftMax[i][mid])\n",
    "                leftMax[i][j] = max(leftMax[i][j - 1], dp[i][j] + presum[j + 1] - presum[i])   \n",
    "                rightMax[i][j] = max(rightMax[i + 1][j], dp[i][j] + presum[j + 1] - presum[i])\n",
    "        return dp[0][-1]             \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "        points = [[0] * n for _ in range(n)]\n",
    "        mxl = [[0] * n for _ in range(n)]\n",
    "        mxr = [[0] * n for _ in range(n)]\n",
    "        prefix = [0]\n",
    "\n",
    "        for i in range(n):\n",
    "            points[i][i] = i\n",
    "            mxl[i][i] = stoneValue[i]\n",
    "            mxr[i][i] = stoneValue[i]\n",
    "            prefix.append(prefix[-1] + stoneValue[i])\n",
    "        for i in range(n - 1):\n",
    "            for j in range(i + 1, n):\n",
    "                k = points[i][j - 1]\n",
    "                total = prefix[j + 1] - prefix[i]\n",
    "                while total - prefix[k + 1] + prefix[i] > prefix[k + 1] - prefix[i]:\n",
    "                    k += 1\n",
    "                points[i][j] = k\n",
    "        print(points) \n",
    "        for j in range(1, n):\n",
    "            for i in range(j - 1, -1, -1):\n",
    "                k = points[i][j]\n",
    "                left, right = prefix[k + 1] - prefix[i], prefix[j + 1] - prefix[k + 1]\n",
    "                if left == right:\n",
    "                    dp[i][j] = max(dp[i][j], mxl[i][k], mxr[k + 1][j])\n",
    "                else:\n",
    "                    if k > i:\n",
    "                        dp[i][j] = max(dp[i][j], mxl[i][k - 1])\n",
    "                    if k < j:\n",
    "                        dp[i][j] = max(dp[i][j], mxr[k + 1][j])\n",
    "                \n",
    "                mxl[i][j] = max(mxl[i][j - 1], dp[i][j] + prefix[j + 1] - prefix[i])\n",
    "                mxr[i][j] = max(mxr[i + 1][j], dp[i][j] + prefix[j + 1] - prefix[i])\n",
    "        \n",
    "        return dp[0][-1]\n",
    "\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from itertools import accumulate\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        add_sum = list(accumulate(stoneValue, initial=0))\n",
    "        g = [[0]*n for _ in range(n)]\n",
    "        s = [[0]*n for _ in range(n)]\n",
    "        dp = [[0]*n for _ in range(n)]\n",
    "        maxl = [[0]*n for _ in range(n)]\n",
    "        maxr = [[0]*n for _ in range(n)]\n",
    "        # f(l,r)+sum(l,r)\n",
    "\n",
    "        for i in range(n):\n",
    "            s[i][i] = stoneValue[i]\n",
    "            g[i][i] = i\n",
    "            for j in range(i+1, n):\n",
    "                s[i][j] = s[i][j-1] + stoneValue[j]\n",
    "                now = g[i][j-1]\n",
    "                while s[i][j] > 2*s[i][now]:\n",
    "                    now += 1\n",
    "                g[i][j] = now\n",
    "        \n",
    "        for i in range(n):\n",
    "            dp[i][i] = 0\n",
    "            maxl[i][i] = s[i][i] + dp[i][i]\n",
    "            maxr[i][i] = s[i][i] + dp[i][i]\n",
    "        for L in range(2,n+1):\n",
    "            for i in range(n-L+1):\n",
    "                l,r = i,i+L-1\n",
    "                mid = g[l][r]\n",
    "                if mid < r and s[l][mid]==s[mid+1][r]:\n",
    "                    dp[l][r] = max(dp[l][r], maxl[l][mid])\n",
    "                    dp[l][r] = max(dp[l][r], maxr[mid+1][r])\n",
    "                else:\n",
    "                    if mid>l:\n",
    "                        dp[l][r] = max(dp[l][r], maxl[l][mid-1])\n",
    "                    if mid<r:\n",
    "                        dp[l][r] = max(dp[l][r], maxr[mid+1][r])\n",
    "                \n",
    "                v = dp[l][r] + s[l][r]\n",
    "                maxl[l][r] = max(v, maxl[l][r-1])\n",
    "                maxr[l][r] = max(v, maxr[l+1][r])\n",
    "\n",
    "        return dp[0][n-1]\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "                "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from itertools import accumulate\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        add_sum = list(accumulate(stoneValue, initial=0))\n",
    "        g = [[0]*n for _ in range(n)]\n",
    "        s = [[0]*n for _ in range(n)]\n",
    "        dp = [[0]*n for _ in range(n)]\n",
    "        maxl = [[0]*n for _ in range(n)]\n",
    "        maxr = [[0]*n for _ in range(n)]\n",
    "        # f(l,r)+sum(l,r)\n",
    "\n",
    "        def cal(left, right)->int:\n",
    "            target = add_sum[right+1]-add_sum[left]\n",
    "            lo = left\n",
    "            ans = -1\n",
    "            while left<=right:\n",
    "                mid = (left+right)//2\n",
    "                if 2*(add_sum[mid+1]-add_sum[lo])>=target:\n",
    "                    ans = mid\n",
    "                    right = mid - 1\n",
    "                else:\n",
    "                    left = mid + 1\n",
    "            return ans\n",
    "\n",
    "        for i in range(n):\n",
    "            s[i][i] = stoneValue[i]\n",
    "            g[i][i] = i\n",
    "        for L in range(2,n+1):\n",
    "            for i in range(n-L+1):\n",
    "                l,r = i,i+L-1\n",
    "                s[l][r] = add_sum[r+1]-add_sum[l]\n",
    "                g[l][r] = cal(l,r)\n",
    "        \n",
    "        for i in range(n):\n",
    "            dp[i][i] = 0\n",
    "            maxl[i][i] = s[i][i] + dp[i][i]\n",
    "            maxr[i][i] = s[i][i] + dp[i][i]\n",
    "        for L in range(2,n+1):\n",
    "            for i in range(n-L+1):\n",
    "                l,r = i,i+L-1\n",
    "                mid = g[l][r]\n",
    "                if mid < r and s[l][mid]==s[mid+1][r]:\n",
    "                    dp[l][r] = max(dp[l][r], maxl[l][mid])\n",
    "                    dp[l][r] = max(dp[l][r], maxr[mid+1][r])\n",
    "                else:\n",
    "                    if mid>l:\n",
    "                        dp[l][r] = max(dp[l][r], maxl[l][mid-1])\n",
    "                    if mid<r:\n",
    "                        dp[l][r] = max(dp[l][r], maxr[mid+1][r])\n",
    "                \n",
    "                v = dp[l][r] + s[l][r]\n",
    "                maxl[l][r] = max(v, maxl[l][r-1])\n",
    "                maxr[l][r] = max(v, maxr[l+1][r])\n",
    "\n",
    "        return dp[0][n-1]\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "                "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "\n",
    "        stoneValue = [0] + stoneValue\n",
    "        pre = list(accumulate(stoneValue))\n",
    "        @cache\n",
    "        def f(i, j):\n",
    "            M = 0 \n",
    "            for k in range(i, j+1):\n",
    "                s = 0 \n",
    "                left = pre[k] - pre[i-1]\n",
    "                right = pre[j] - pre[k]\n",
    "                if left > right:\n",
    "                    if 2 * right <= M:\n",
    "                        break\n",
    "                    s += right \n",
    "                    s += f(k+1, j)\n",
    "                elif left < right:\n",
    "                    if 2 * left <= M:\n",
    "                        continue\n",
    "                    s += left \n",
    "                    s += f(i, k)\n",
    "                else:\n",
    "                    s += left \n",
    "                    s += max(f(i, k), f(k+1, j))\n",
    "                M = max(M, s)\n",
    "            return M\n",
    "        return f(1, len(stoneValue)-1)\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        \n",
    "        \n",
    "        pres = list(accumulate(stoneValue, initial=0))\n",
    "        n = len(stoneValue)\n",
    "        \n",
    "        @cache\n",
    "        def dfs(l, r):\n",
    "            # print(l, r)\n",
    "            if l >= r:\n",
    "                return 0\n",
    "            res = -inf\n",
    "            for i in range(l, r):\n",
    "                left, right = pres[i + 1] - pres[l], pres[r + 1] - pres[i + 1]\n",
    "                if left == right:\n",
    "                    res = max(res, dfs(l, i) + left, dfs(i + 1, r) + right)\n",
    "                elif left < right:\n",
    "                    if res >= 2 * left:\n",
    "                        continue\n",
    "                    res = max(res, dfs(l, i) + left)\n",
    "                else:\n",
    "                    if 2 * right <= res:\n",
    "                        break\n",
    "                    res = max(res, dfs(i + 1, r) + right)\n",
    "            return res\n",
    "        \n",
    "        return dfs(0, n - 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        # 前缀和\n",
    "        S = [0]*(n+1)\n",
    "        for i in range(1,n+1):\n",
    "            S[i] = S[i-1] + stoneValue[i-1]\n",
    "        @cache\n",
    "        def dfs(i,j):\n",
    "            if i >= j:\n",
    "                return 0\n",
    "            total = S[j+1] - S[i]\n",
    "            sum = 0\n",
    "            count = 0\n",
    "            for k in range(i,j+1):\n",
    "                sum += stoneValue[k]\n",
    "                if sum == total-sum:\n",
    "                    count = max(sum + max(dfs(i,k),dfs(k+1,j)),count)\n",
    "                elif sum < total-sum:\n",
    "                    # 剪个枝\n",
    "                    if count >= 2*sum:\n",
    "                        continue\n",
    "                    count = max(sum+dfs(i,k),count)\n",
    "                else:\n",
    "                    # 剪个枝\n",
    "                    if 2*(total - sum) <= count:\n",
    "                        break\n",
    "                    count = max(count,total-sum+dfs(k+1,j))\n",
    "            return count    \n",
    "        return dfs(0,n-1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        pre = list(accumulate(stoneValue))\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def dfs(l,r):\n",
    "            if l >= r:\n",
    "                return 0\n",
    "            ans = 0\n",
    "            for i in range(l,r):\n",
    "                #处理 l-1 < 0\n",
    "                sum1 = pre[i] - (pre[l-1] if l!=0 else 0)\n",
    "                sum2 = pre[r] - pre[i]\n",
    "                if sum1 > sum2:\n",
    "                    if 2*sum2 <= ans:\n",
    "                        break\n",
    "                    ans = max(ans,sum2 + dfs(i+1,r))\n",
    "                elif sum1 < sum2:\n",
    "                    if ans >= 2*sum1:\n",
    "                        continue\n",
    "                    ans = max(ans,sum1 + dfs(l,i))\n",
    "                else:\n",
    "                    ans = max(ans,max(dfs(i+1,r),dfs(l,i))+sum1)\n",
    "            return ans\n",
    "        return dfs(0,len(stoneValue)-1)\n",
    "\n",
    "# class Solution:\n",
    "#     def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "#         @lru_cache(None)\n",
    "#         def dfs(left: int, right: int) -> int:\n",
    "#             if left == right:\n",
    "#                 return 0\n",
    "            \n",
    "#             total = sum(stoneValue[left:right+1])\n",
    "#             suml = ans = 0\n",
    "#             for i in range(left, right):\n",
    "#                 suml += stoneValue[i]\n",
    "#                 sumr = total - suml\n",
    "#                 if suml < sumr:\n",
    "#                     ans = max(ans, dfs(left, i) + suml)\n",
    "#                 elif suml > sumr:\n",
    "#                     ans = max(ans, dfs(i + 1, right) + sumr)\n",
    "#                 else:\n",
    "#                     ans = max(ans, max(dfs(left, i), dfs(i + 1, right)) + suml)\n",
    "#             return ans\n",
    "        \n",
    "#         n = len(stoneValue)\n",
    "#         return dfs(0, n - 1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        \n",
    "        \n",
    "        pres = list(accumulate(stoneValue, initial=0))\n",
    "        n = len(stoneValue)\n",
    "        \n",
    "        @cache\n",
    "        def dfs(l, r):\n",
    "            # print(l, r)\n",
    "            if l >= r:\n",
    "                return 0\n",
    "            res = -inf\n",
    "            for i in range(l, r):\n",
    "                left, right = pres[i + 1] - pres[l], pres[r + 1] - pres[i + 1]\n",
    "                if left == right:\n",
    "                    res = max(res, dfs(l, i) + left, dfs(i + 1, r) + right)\n",
    "                elif left < right:\n",
    "                    if res >= 2 * left:\n",
    "                        continue\n",
    "                    res = max(res, dfs(l, i) + left)\n",
    "                else:\n",
    "                    if 2 * right <= res:\n",
    "                        break\n",
    "                    res = max(res, dfs(i + 1, r) + right)\n",
    "            return res\n",
    "        \n",
    "        return dfs(0, n - 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        # 前缀和\n",
    "        S = [0]*(n+1)\n",
    "        for i in range(1,n+1):\n",
    "            S[i] = S[i-1] + stoneValue[i-1]\n",
    "        @cache\n",
    "        def dfs(i,j):\n",
    "            if i >= j:\n",
    "                return 0\n",
    "            total = S[j+1] - S[i]\n",
    "            sum = 0\n",
    "            count = 0\n",
    "            for k in range(i,j+1):\n",
    "                sum += stoneValue[k]\n",
    "                if sum == total-sum:\n",
    "                    count = max(sum + max(dfs(i,k),dfs(k+1,j)),count)\n",
    "                elif sum < total-sum:\n",
    "                    # 剪个枝\n",
    "                    if count >= 2*sum:\n",
    "                        continue\n",
    "                    count = max(sum+dfs(i,k),count)\n",
    "                else:\n",
    "                    # 剪个枝\n",
    "                    if 2*(total - sum) <= count:\n",
    "                        break\n",
    "                    count = max(count,total-sum+dfs(k+1,j))\n",
    "            return count    \n",
    "        return dfs(0,n-1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        # 前缀和\n",
    "        S = [0]*(n+1)\n",
    "        for i in range(1,n+1):\n",
    "            S[i] = S[i-1] + stoneValue[i-1]\n",
    "        @cache\n",
    "        def dfs(i,j):\n",
    "            if i >= j:\n",
    "                return 0\n",
    "            total = S[j+1] - S[i]\n",
    "            sum = 0\n",
    "            count = 0\n",
    "            for k in range(i,j+1):\n",
    "                sum += stoneValue[k]\n",
    "                if sum == total-sum:\n",
    "                    count = max(sum + max(dfs(i,k),dfs(k+1,j)),count)\n",
    "                elif sum < total-sum:\n",
    "                    # 剪个枝\n",
    "                    if count >= 2*sum:\n",
    "                        continue\n",
    "                    count = max(sum+dfs(i,k),count)\n",
    "                else:\n",
    "                    # 剪个枝\n",
    "                    if 2*(total - sum) <= count:\n",
    "                        break\n",
    "                    count = max(count,total-sum+dfs(k+1,j))\n",
    "            return count    \n",
    "        return dfs(0,n-1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        sums = [0]\n",
    "        for i in stoneValue:\n",
    "            sums.append(i+sums[-1])\n",
    "\n",
    "        dp = [[(0, i) for __ in range(len(stoneValue)+1)] for i in range(len(stoneValue))]\n",
    "        for left in range(n-2, -1, -1):\n",
    "            for right in range(left+2, n+1):\n",
    "                p, q = sorted([dp[left+1][right][1], dp[left][right-1][1]])\n",
    "                for a in range(max(0, p-1), min(q+2, n)):\n",
    "                    l1, r1 = sums[a]-sums[left], sums[right]-sums[a]\n",
    "                    if l1 == r1:\n",
    "                        dp[left][right] = max(dp[left][right], (max(dp[left][a][0], dp[a][right][0])+l1, a))\n",
    "                    elif l1 > r1:\n",
    "                        dp[left][right] = max(dp[left][right], (dp[a][right][0]+r1, a))\n",
    "                    else:\n",
    "                        dp[left][right] = max(dp[left][right], (dp[left][a][0]+l1, a))\n",
    "        return dp[0][-1][0]\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        sumv = [[0]*n for i in range(n)]\n",
    "        dp = [[0]*n for i in range(n)]\n",
    "        maxl = [[0]*n for i in range(n)]\n",
    "        maxr = [[0]*n for i in range(n)]\n",
    "        fenge = [[0]*n for i in range(n)]\n",
    "        for i in range(n):\n",
    "            sumv[i][i] = stoneValue[i]\n",
    "            maxl[i][i] = stoneValue[i]\n",
    "            maxr[i][i] = stoneValue[i]\n",
    "            fenge[i][i] = i+1\n",
    "        for l in range(1, n):\n",
    "            for i in range(n-l):\n",
    "                j = i+l\n",
    "                sumv[i][j] = sumv[i][j-1]+stoneValue[j]\n",
    "                dp[i][j] = -inf\n",
    "                fenge[i][j] = fenge[i][j-1]\n",
    "                while fenge[i][j] <= j and sumv[i][fenge[i][j]-1] <= sumv[fenge[i][j]][j]:\n",
    "                    fenge[i][j] += 1\n",
    "                fenge[i][j] -= 1\n",
    "                if fenge[i][j] > i and sumv[i][fenge[i][j]-1] <= sumv[fenge[i][j]][j]:\n",
    "                    dp[i][j] = max(dp[i][j], maxl[i][fenge[i][j]-1])\n",
    "                while fenge[i][j] > i and sumv[i][fenge[i][j]-1] >= sumv[fenge[i][j]][j]:\n",
    "                    fenge[i][j] -= 1\n",
    "                fenge[i][j] += 1\n",
    "                if fenge[i][j] <= j and sumv[i][fenge[i][j]-1] >= sumv[fenge[i][j]][j]:\n",
    "                    dp[i][j] = max(dp[i][j], maxr[fenge[i][j]][j])\n",
    "                maxl[i][j] = max(maxl[i][j-1], sumv[i][j] + dp[i][j])\n",
    "                maxr[i][j] = max(maxr[i+1][j], sumv[i][j] + dp[i][j])\n",
    "        return dp[0][n-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        presum=list(accumulate(stoneValue,initial=0))\n",
    "        @cache\n",
    "        def dfs(left,right):\n",
    "            ans=0            \n",
    "            for mid in range(left,right):\n",
    "                t1=presum[mid]-presum[left]\n",
    "                t2=presum[right]-presum[mid]\n",
    "                if t1<t2:\n",
    "                    if ans>=2*t1:continue\n",
    "                    ans=max(ans,dfs(left,mid)+t1)\n",
    "                elif t1>t2:\n",
    "                    if ans>=2*t2:continue\n",
    "                    ans=max(ans,dfs(mid,right)+t2)\n",
    "                else:##t1==t2\n",
    "                    ans=max(ans,dfs(left,mid)+t1,dfs(mid,right)+t2)\n",
    "                    break\n",
    "            return ans\n",
    "        return dfs(0,len(stoneValue))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        sums = [0] * (n + 1)\n",
    "        for i in range(n):\n",
    "            sums[i + 1] = sums[i] + stoneValue[i]\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def get(l, r):\n",
    "            if l == r:\n",
    "                return 0\n",
    "            res = 0\n",
    "            for j in range(l, r):\n",
    "                t0 = sums[j + 1] - sums[l]\n",
    "                t1 = sums[r + 1] - sums[j + 1]\n",
    "                t = min(t0, t1)\n",
    "                if t * 2 <= res:\n",
    "                    break\n",
    "                if t0 > t1:\n",
    "                    temp = get(j + 1, r) + t1\n",
    "                elif t0 < t1:\n",
    "                    temp = get(l, j) + t0\n",
    "                else:\n",
    "                    temp = t0 + max(get(j + 1, r), get(l, j))\n",
    "                res = max(res, temp)\n",
    "            return res\n",
    "\n",
    "        ans = get(0, n - 1)\n",
    "        return ans\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        s = list(itertools.accumulate(stoneValue, initial=0))\n",
    "        @cache\n",
    "        def f(i, j):\n",
    "            if i >= j:\n",
    "                return 0\n",
    "            a, b = 0, s[j+1] - s[i]\n",
    "            # ans = min(f(i+1, j), f(i, j-1))\n",
    "            ans = 0\n",
    "            for k in range(i, j):\n",
    "                a += stoneValue[k]\n",
    "                b -= stoneValue[k]\n",
    "                if 2 * a < ans:\n",
    "                    continue\n",
    "                if 2 * b < ans:\n",
    "                    break\n",
    "                if a <= b and (x := f(i, k) + a) > ans:\n",
    "                    ans = x\n",
    "                if a >= b and (x := f(k+1, j) + b) > ans:\n",
    "                    ans = x\n",
    "            return ans\n",
    "        \n",
    "        return f(0, n-1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        sums = [0] * (n + 1)\n",
    "        for i in range(n):\n",
    "            sums[i + 1] = sums[i] + stoneValue[i]\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def get(l, r):\n",
    "            if l == r:\n",
    "                return 0\n",
    "            res = 0\n",
    "            for j in range(l, r):\n",
    "                t0 = sums[j + 1] - sums[l]\n",
    "                t1 = sums[r + 1] - sums[j + 1]\n",
    "                t = min(t0, t1)\n",
    "                if t * 2 < res:\n",
    "                    break\n",
    "                if t0 > t1:\n",
    "                    temp = get(j + 1, r) + t1\n",
    "                elif t0 < t1:\n",
    "                    temp = get(l, j) + t0\n",
    "                else:\n",
    "                    temp = t0 + max(get(j + 1, r), get(l, j))\n",
    "                res = max(res, temp)\n",
    "            return res\n",
    "\n",
    "        ans = get(0, n - 1)\n",
    "        return ans\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n=len(stoneValue)\n",
    "        pre=[0]*(n+1)\n",
    "        for i,e in enumerate(stoneValue):\n",
    "            pre[i+1]=pre[i]+e\n",
    "        print(pre)\n",
    "        @cache    \n",
    "        def dfs(l,r):\n",
    "            if l==r:\n",
    "                return 0\n",
    "            if r-l==1:\n",
    "                return min(stoneValue[l],stoneValue[r])\n",
    "            total=pre[r+1]-pre[l]\n",
    "            res=ls=0\n",
    "            for last in range(l,r):\n",
    "                ls+=stoneValue[last]\n",
    "                rs=total-ls     \n",
    "                if ls>rs:\n",
    "                    dr=dfs(last+1,r)\n",
    "                    if dr+rs>res:\n",
    "                        res=dr+rs\n",
    "                elif ls<rs:\n",
    "                    dr=dfs(l,last)\n",
    "                    if dr+ls>res:\n",
    "                        res=dr+ls\n",
    "                else:\n",
    "                    dr=max(dfs(last+1,r)+rs,dfs(l,last)+ls)\n",
    "                    if dr>res:\n",
    "                        res=dr\n",
    "            #print(l,r,res)\n",
    "            return res\n",
    "        return dfs(0,n-1)\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        n = len(stoneValue)\n",
    "        s = list(itertools.accumulate(stoneValue, initial=0))\n",
    "        @cache\n",
    "        def f(i, j):\n",
    "            if i == j:\n",
    "                return 0\n",
    "            a, b = 0, s[j+1] - s[i]\n",
    "            ans = 0\n",
    "            for k in range(i, j):\n",
    "                a += stoneValue[k]\n",
    "                b -= stoneValue[k]\n",
    "                if a <= b and (x := f(i, k) + a) > ans:\n",
    "                    ans = x\n",
    "                if a >= b and (x := f(k+1, j) + b) > ans:\n",
    "                    ans = x\n",
    "            return ans\n",
    "        \n",
    "        return f(0, n-1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: list[int]) -> int:\n",
    "        @lru_cache(None)\n",
    "        def dfs(i,j):\n",
    "            if i>=j:\n",
    "                return 0\n",
    "            ans=0\n",
    "            half=(presum[j+1]+presum[i])/2\n",
    "            idx=bisect.bisect_left(presum,half,lo=i,hi=j+1)\n",
    "            if presum[idx]==half:\n",
    "                ans=max(ans,left_dfs(i,idx),right_dfs(idx,j))\n",
    "            else:\n",
    "                ans=max(ans,left_dfs(i,idx-1))\n",
    "                ans=max(ans,right_dfs(idx,j))\n",
    "            return ans\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def left_dfs(i,j):\n",
    "            if i>=j:\n",
    "                return 0\n",
    "            return max(presum[j]-presum[i]+dfs(i,j-1),left_dfs(i,j-1))\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def right_dfs(i,j):\n",
    "            if i>=j+1:\n",
    "                return 0\n",
    "            return max(presum[j+1]-presum[i]+dfs(i,j),right_dfs(i+1,j))\n",
    "\n",
    "        presum=[0]+list(accumulate(stoneValue))\n",
    "        return dfs(0,len(stoneValue)-1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        @lru_cache(None)\n",
    "        def dfs(i, j):\n",
    "            if i >= j:\n",
    "                return 0\n",
    "            ans = 0\n",
    "            half = (presum[j + 1] + presum[i]) / 2\n",
    "            # 使用二分查找左右的大小中心位置\n",
    "            idx = bisect.bisect_left(presum, half, lo=i, hi=j + 1)\n",
    "            # idx 左边, left更小; idx 右边, right更小\n",
    "            if presum[idx] == half:\n",
    "                ans = max(ans, left_dfs(i, idx), right_dfs(idx, j))\n",
    "            else:\n",
    "                ans = max(ans, left_dfs(i, idx-1))\n",
    "                ans = max(ans, right_dfs(idx, j))\n",
    "            return ans\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def left_dfs(i, j):\n",
    "            if i >= j:\n",
    "                return 0\n",
    "            return max(presum[j] - presum[i] + dfs(i, j-1), left_dfs(i, j-1))\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def right_dfs(i, j):\n",
    "            if i >= j+1:\n",
    "                return 0\n",
    "            return max(presum[j+1] - presum[i] + dfs(i, j), right_dfs(i+1, j))\n",
    "\n",
    "        presum = [0] + list(accumulate(stoneValue))\n",
    "        return dfs(0, len(stoneValue) - 1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        @lru_cache(None)\n",
    "        def dfs(i, j):\n",
    "            if i >= j:\n",
    "                return 0\n",
    "            ans = 0\n",
    "            half = (presum[j + 1] + presum[i]) / 2\n",
    "            # 使用二分查找左右的大小中心位置\n",
    "            idx = bisect.bisect_left(presum, half, lo=i, hi=j + 1)\n",
    "            # idx 左边, left更小; idx 右边, right更小\n",
    "            if presum[idx] == half:\n",
    "                ans = max(ans, left_dfs(i, idx), right_dfs(idx, j))\n",
    "            else:\n",
    "                ans = max(ans, left_dfs(i, idx-1))\n",
    "                ans = max(ans, right_dfs(idx, j))\n",
    "            return ans\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def left_dfs(i, j):\n",
    "            if i >= j:\n",
    "                return 0\n",
    "            return max(presum[j] - presum[i] + dfs(i, j-1), left_dfs(i, j-1))\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def right_dfs(i, j):\n",
    "            if i >= j+1:\n",
    "                return 0\n",
    "            return max(presum[j+1] - presum[i] + dfs(i, j), right_dfs(i+1, j))\n",
    "\n",
    "        presum = [0] + list(accumulate(stoneValue))\n",
    "        return dfs(0, len(stoneValue) - 1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        @lru_cache(None)\n",
    "        def dfs(i, j):\n",
    "            if i >= j:\n",
    "                return 0\n",
    "            ans = 0\n",
    "            half = (presum[j + 1] + presum[i]) / 2\n",
    "            # 使用二分查找左右的大小中心位置\n",
    "            idx = bisect.bisect_left(presum, half, lo=i, hi=j + 1)\n",
    "            # idx 左边, left更小; idx 右边, right更小\n",
    "            if presum[idx] == half:\n",
    "                ans = max(ans, left_dfs(i, idx), right_dfs(idx, j))\n",
    "            else:\n",
    "                ans = max(ans, left_dfs(i, idx-1))\n",
    "                ans = max(ans, right_dfs(idx, j))\n",
    "            return ans\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def left_dfs(i, j):\n",
    "            if i >= j:\n",
    "                return 0\n",
    "            return max(presum[j] - presum[i] + dfs(i, j-1), left_dfs(i, j-1))\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def right_dfs(i, j):\n",
    "            if i >= j+1:\n",
    "                return 0\n",
    "            return max(presum[j+1] - presum[i] + dfs(i, j), right_dfs(i+1, j))\n",
    "\n",
    "        presum = [0] + list(accumulate(stoneValue))\n",
    "        return dfs(0, len(stoneValue) - 1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        @lru_cache(None)\n",
    "        def dfs(i, j):\n",
    "            if i >= j:\n",
    "                return 0\n",
    "            ans = 0\n",
    "            half = (presum[j + 1] + presum[i]) / 2\n",
    "            # 使用二分查找左右的大小中心位置\n",
    "            idx = bisect.bisect_left(presum, half, lo=i, hi=j + 1)\n",
    "            # idx 左边, left更小; idx 右边, right更小\n",
    "            if presum[idx] == half:\n",
    "                ans = max(ans, left_dfs(i, idx), right_dfs(idx, j))\n",
    "            else:\n",
    "                ans = max(ans, left_dfs(i, idx-1))\n",
    "                ans = max(ans, right_dfs(idx, j))\n",
    "            return ans\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def left_dfs(i, j):\n",
    "            if i >= j:\n",
    "                return 0\n",
    "            return max(presum[j] - presum[i] + dfs(i, j-1), left_dfs(i, j-1))\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def right_dfs(i, j):\n",
    "            if i >= j+1:\n",
    "                return 0\n",
    "            return max(presum[j+1] - presum[i] + dfs(i, j), right_dfs(i+1, j))\n",
    "\n",
    "        presum = [0] + list(accumulate(stoneValue))\n",
    "        return dfs(0, len(stoneValue) - 1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        @lru_cache(None)\n",
    "        def dfs(i, j):\n",
    "            if i >= j:\n",
    "                return 0\n",
    "            ans = 0\n",
    "            half = (presum[j + 1] + presum[i]) / 2\n",
    "            # 使用二分查找左右的大小中心位置\n",
    "            idx = bisect.bisect_left(presum, half, lo=i, hi=j + 1)\n",
    "            # idx 左边, left更小; idx 右边, right更小\n",
    "            if presum[idx] == half:\n",
    "                ans = max(ans, left_dfs(i, idx), right_dfs(idx, j))\n",
    "            else:\n",
    "                ans = max(ans, left_dfs(i, idx-1))\n",
    "                ans = max(ans, right_dfs(idx, j))\n",
    "            return ans\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def left_dfs(i, j):\n",
    "            if i >= j:\n",
    "                return 0\n",
    "            return max(presum[j] - presum[i] + dfs(i, j-1), left_dfs(i, j-1))\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def right_dfs(i, j):\n",
    "            if i >= j+1:\n",
    "                return 0\n",
    "            return max(presum[j+1] - presum[i] + dfs(i, j), right_dfs(i+1, j))\n",
    "\n",
    "        presum = [0] + list(accumulate(stoneValue))\n",
    "        return dfs(0, len(stoneValue) - 1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        @lru_cache(None)\n",
    "        def dfs(i, j):\n",
    "            if i >= j:\n",
    "                return 0\n",
    "            ans = 0\n",
    "            half = (presum[j + 1] + presum[i]) / 2\n",
    "            # 使用二分查找左右的大小中心位置\n",
    "            idx = bisect.bisect_left(presum, half, lo=i, hi=j + 1)\n",
    "            # idx 左边, left更小; idx 右边, right更小\n",
    "            if presum[idx] == half:\n",
    "                ans = max(ans, left_dfs(i, idx), right_dfs(idx, j))\n",
    "            else:\n",
    "                ans = max(ans, left_dfs(i, idx-1))\n",
    "                ans = max(ans, right_dfs(idx, j))\n",
    "            return ans\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def left_dfs(i, j):\n",
    "            if i >= j:\n",
    "                return 0\n",
    "            return max(presum[j] - presum[i] + dfs(i, j-1), left_dfs(i, j-1))\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def right_dfs(i, j):\n",
    "            if i >= j+1:\n",
    "                return 0\n",
    "            return max(presum[j+1] - presum[i] + dfs(i, j), right_dfs(i+1, j))\n",
    "\n",
    "        presum = [0] + list(accumulate(stoneValue))\n",
    "        return dfs(0, len(stoneValue) - 1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameV(self, stoneValue: List[int]) -> int:\n",
    "        @lru_cache(None)\n",
    "        def dfs(i, j):\n",
    "            if i >= j:\n",
    "                return 0\n",
    "            ans = 0\n",
    "            half = (presum[j + 1] + presum[i]) / 2\n",
    "            # 使用二分查找左右的大小中心位置\n",
    "            idx = bisect.bisect_left(presum, half, lo=i, hi=j + 1)\n",
    "            # idx 左边, left更小; idx 右边, right更小\n",
    "            if presum[idx] == half:\n",
    "                ans = max(ans, left_dfs(i, idx), right_dfs(idx, j))\n",
    "            else:\n",
    "                ans = max(ans, left_dfs(i, idx-1))\n",
    "                ans = max(ans, right_dfs(idx, j))\n",
    "            return ans\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def left_dfs(i, j):\n",
    "            if i >= j:\n",
    "                return 0\n",
    "            return max(presum[j] - presum[i] + dfs(i, j-1), left_dfs(i, j-1))\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def right_dfs(i, j):\n",
    "            if i >= j+1:\n",
    "                return 0\n",
    "            return max(presum[j+1] - presum[i] + dfs(i, j), right_dfs(i+1, j))\n",
    "\n",
    "        presum = [0] + list(accumulate(stoneValue))\n",
    "        return dfs(0, len(stoneValue) - 1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n=len(aliceValues)\n",
    "        a=[0]*n\n",
    "        alice=0\n",
    "        bobva=0\n",
    "        for i in range(n):\n",
    "            a[i]=aliceValues[i]+bobValues[i]\n",
    "        a.sort(reverse=True)\n",
    "        alice=sum(a[::2])\n",
    "        bobva=sum(bobValues)\n",
    "        if alice>bobva:\n",
    "            return 1\n",
    "        elif alice<bobva:\n",
    "            return -1\n",
    "        else:\n",
    "            return 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n=len(aliceValues)\n",
    "        a=[0]*n\n",
    "        alice=0\n",
    "        bobva=0\n",
    "        for i in range(n):\n",
    "            a[i]=aliceValues[i]+bobValues[i]\n",
    "        a.sort(reverse=True)\n",
    "        alice=sum(a[::2])\n",
    "        bobva=sum(bobValues)\n",
    "        if alice>bobva:\n",
    "            return 1\n",
    "        elif alice<bobva:\n",
    "            return -1\n",
    "        else:\n",
    "            return 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        totalValues = [(a+b) for a,b in zip(aliceValues, bobValues)]\n",
    "        totalValues.sort(reverse=True)\n",
    "        # 所有Alice能拿到的石头的总价值，其中每个都多拿了Bob的对应石子,再减去本来就是Bob拿的石子，正好是Bob的所有石子\n",
    "        ans = sum(totalValues[::2]) - sum(bobValues)\n",
    "        if ans > 0:\n",
    "            return 1\n",
    "        elif ans < 0:\n",
    "            return -1\n",
    "        return 0\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        total_values = [(a+b) for a,b in zip(aliceValues,bobValues)]\n",
    "        total_values.sort(reverse = True)\n",
    "        ans = sum(total_values[::2]) - sum(bobValues)\n",
    "        if ans > 0:\n",
    "            return 1\n",
    "        elif ans == 0:\n",
    "            return 0\n",
    "        else:\n",
    "            return -1\n",
    "            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        # 记录两个值和并且降序\n",
    "        totalValue = [(a + b) for a, b in zip(aliceValues, bobValues)]\n",
    "        totalValue.sort(reverse=True)\n",
    "        ans = sum(totalValue[::2]) - sum(bobValues)\n",
    "        if ans > 0:\n",
    "            return 1\n",
    "        elif ans == 0:\n",
    "            return 0\n",
    "        else:\n",
    "            return -1\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        lst=[(a+b) for a,b in zip(aliceValues,bobValues)]\n",
    "        lst.sort(reverse=True)\n",
    "        ans=sum(lst[::2])-sum(bobValues)\n",
    "        if ans>0:\n",
    "            return 1\n",
    "        elif ans==0:\n",
    "            return 0\n",
    "        else:\n",
    "            return -1\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        nums = [x+y for x,y in zip(aliceValues,bobValues)]\n",
    "        nums.sort(reverse=True)\n",
    "        ans = sum(nums[::2]) - sum(bobValues)\n",
    "        if ans > 0:\n",
    "            return 1\n",
    "        elif ans < 0:\n",
    "            return -1\n",
    "        else:\n",
    "            return 0\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        totalValues = [(a+b) for a,b in zip(aliceValues, bobValues)]\n",
    "        totalValues.sort(reverse=True)\n",
    "        # 所有Alice能拿到的石头的总价值，其中每个都多拿了Bob的对应石子,再减去本来就是Bob拿的石子，正好是Bob的所有石子\n",
    "        ans = sum(totalValues[::2]) - sum(bobValues)\n",
    "        if ans > 0:\n",
    "            return 1\n",
    "        elif ans < 0:\n",
    "            return -1\n",
    "        return 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        a = [aliceValues[i] + bobValues[i] for i in range(n)]\n",
    "        a.sort(reverse = True)\n",
    "        flag = (sum(aliceValues) - sum(bobValues)) + (sum(a[::2]) - sum(a[1::2]))\n",
    "        if flag > 0:\n",
    "            return 1\n",
    "        elif flag < 0:\n",
    "            return -1\n",
    "        else:\n",
    "            return 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        totalValues = [(a+b) for a,b in zip(aliceValues, bobValues)]\n",
    "        totalValues.sort(reverse=True)\n",
    "        # 所有Alice能拿到的石头的总价值，其中每个都多拿了Bob的对应石子,再减去本来就是Bob拿的石子，正好是Bob的所有石子\n",
    "        ans = sum(totalValues[::2]) - sum(bobValues)\n",
    "        if ans > 0:\n",
    "            return 1\n",
    "        elif ans < 0:\n",
    "            return -1\n",
    "        return 0\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        total = sum(bobValues)\n",
    "        addValues = [aliceValues[i] + bobValues[i] for i in range(n)]\n",
    "        addValues.sort(reverse=True)\n",
    "        diff = sum(addValues[::2]) - total\n",
    "        ans = 0\n",
    "        if diff > 0:\n",
    "            ans = 1\n",
    "        if diff < 0:\n",
    "            ans = -1\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        total = sum(bobValues)\n",
    "        addValues = [aliceValues[i] + bobValues[i] for i in range(n)]\n",
    "        addValues.sort(reverse=True)\n",
    "        diff = sum(addValues[::2]) - total\n",
    "        ans = 0\n",
    "        if diff > 0:\n",
    "            ans = 1\n",
    "        if diff < 0:\n",
    "            ans = -1\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        total = sum(bobValues)\n",
    "        addValues = [aliceValues[i] + bobValues[i] for i in range(n)]\n",
    "        addValues.sort(reverse=True)\n",
    "        diff = sum(addValues[::2]) - total\n",
    "        ans = 0\n",
    "        if diff > 0:\n",
    "            ans = 1\n",
    "        if diff < 0:\n",
    "            ans = -1\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        total = sum(bobValues)\n",
    "        addValues = [aliceValues[i] + bobValues[i] for i in range(n)]\n",
    "        addValues.sort(reverse=True)\n",
    "        diff = sum(addValues[::2]) - total\n",
    "        ans = 0\n",
    "        if diff > 0:\n",
    "            ans = 1\n",
    "        if diff < 0:\n",
    "            ans = -1\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        totalValues = [(a+b) for a,b in zip(aliceValues, bobValues)]\n",
    "        totalValues.sort(reverse=True)\n",
    "        # 所有Alice能拿到的石头的总价值，其中每个都多拿了Bob的对应石子,再减去本来就是Bob拿的石子，正好是Bob的所有石子\n",
    "        ans = sum(totalValues[::2]) - sum(bobValues)\n",
    "        if ans > 0:\n",
    "            return 1\n",
    "        elif ans < 0:\n",
    "            return -1\n",
    "        return 0\n",
    "\n",
    "# 作者：Benhao\n",
    "# 链接：https://leetcode.cn/problems/stone-game-vi/\n",
    "# 来源：力扣（LeetCode）\n",
    "# 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        a, b = aliceValues, bobValues\n",
    "        n = len(a)\n",
    "        total = sum(b)\n",
    "        a = [a[i] + b[i] for i in range(n)]\n",
    "        a.sort(reverse=True)\n",
    "        diff = sum(a[::2]) - total\n",
    "        ans = 0\n",
    "        if diff > 0:\n",
    "            ans = 1\n",
    "        if diff < 0:\n",
    "            ans = -1\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        total_val = sorted([i+j for i, j in zip(aliceValues, bobValues)], reverse=True)\n",
    "        res = sum(total_val[::2]) - sum(bobValues)\n",
    "        if res > 0:\n",
    "            return 1 \n",
    "        elif res == 0:\n",
    "            return 0 \n",
    "        else:\n",
    "            return -1\n",
    "            \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        # real_val = [i+j for i, j in zip(aliceValues, bobValues)]\n",
    "        # idx = sorted(zip(real_val, list(range(len(aliceValues)))), reverse=True)\n",
    "        # alice, bob = sum(aliceValues[i] for v, i in idx[::2]), sum(bobValues[i] for v, i in idx[1::2])\n",
    "        # if alice > bob:\n",
    "        #     return 1 \n",
    "        # elif alice == bob:\n",
    "        #     return 0 \n",
    "        # else:\n",
    "        #     return -1\n",
    "\n",
    "        # ---------------------------------------\n",
    "        total_val = sorted([i+j for i, j in zip(aliceValues, bobValues)], reverse=True)\n",
    "        res = sum(total_val[::2]) - sum(bobValues)\n",
    "        if res > 0:\n",
    "            return 1 \n",
    "        elif res == 0:\n",
    "            return 0 \n",
    "        else:\n",
    "            return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\r\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\r\n",
    "        # 一个石子要么alice拿，要么bob拿 \r\n",
    "        # alice 可以拿 (n + 1) // 2 个石子 \r\n",
    "        # \r\n",
    "        n = len(aliceValues)\r\n",
    "        ids = [i for i in range(n)]\r\n",
    "        ids.sort(key=lambda i:aliceValues[i] + bobValues[i], reverse=True)\r\n",
    "       \r\n",
    "        \r\n",
    "        alice, bob = 0, 0\r\n",
    "        for i, idx in enumerate(ids):\r\n",
    "            if i % 2 == 0:\r\n",
    "                alice += aliceValues[idx] \r\n",
    "            else:\r\n",
    "                bob += bobValues[idx]\r\n",
    "        if alice > bob:\r\n",
    "            return 1 \r\n",
    "        elif alice == bob:\r\n",
    "            return 0 \r\n",
    "        return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        index = sorted(range(n), key = lambda x: aliceValues[x]+bobValues[x], reverse = True)\n",
    "        cnt = 0\n",
    "        for i in range(n):\n",
    "            if i % 2: cnt -= bobValues[index[i]]\n",
    "            else:   cnt += aliceValues[index[i]]\n",
    "        if cnt > 0: return 1\n",
    "        elif cnt < 0:   return -1\n",
    "        return cnt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        index = sorted(range(n), key = lambda x: aliceValues[x]+bobValues[x], reverse = True)\n",
    "        cnt = 0\n",
    "        for i in range(n):\n",
    "            if i % 2: cnt -= bobValues[index[i]]\n",
    "            else:   cnt += aliceValues[index[i]]\n",
    "        if cnt > 0: return 1\n",
    "        elif cnt < 0:   return -1\n",
    "        return cnt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        index = sorted(range(n), key = lambda x: aliceValues[x]+bobValues[x], reverse = True)\n",
    "        cnt = 0\n",
    "        for i in range(n):\n",
    "            if i % 2: cnt -= bobValues[index[i]]\n",
    "            else:   cnt += aliceValues[index[i]]\n",
    "        if cnt > 0: return 1\n",
    "        elif cnt < 0:   return -1\n",
    "        return cnt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        total = list(range(n))\n",
    "        total.sort(key = lambda i:aliceValues[i] + bobValues[i], reverse = True)\n",
    "        # print(total)\n",
    "        index = (n+1) << 1\n",
    "        x = sum((aliceValues[i] for i in total[::2]))\n",
    "        y = sum(bobValues[i] for i in total[1::2])\n",
    "        # print(x, y)\n",
    "        if x == y:\n",
    "            return 0\n",
    "        elif x > y:\n",
    "            return 1\n",
    "        else:\n",
    "            return -1\n",
    "            \n",
    "\n",
    "\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        total = list(range(n))\n",
    "        total.sort(key = lambda i:aliceValues[i] + bobValues[i], reverse = True)\n",
    "        # print(total)\n",
    "        x = sum((aliceValues[i] for i in total[::2]))\n",
    "        y = sum(bobValues[i] for i in total[1::2])\n",
    "        # print(x, y)\n",
    "        if x == y:\n",
    "            return 0\n",
    "        elif x > y:\n",
    "            return 1\n",
    "        else:\n",
    "            return -1\n",
    "            \n",
    "\n",
    "\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        total = list(range(n))\n",
    "        total.sort(key = lambda i:aliceValues[i] + bobValues[i], reverse = True)\n",
    "        # print(total)\n",
    "        x = sum((aliceValues[i] for i in total[::2]))\n",
    "        y = sum(bobValues[i] for i in total[1::2])\n",
    "        # print(x, y)\n",
    "        if x == y:\n",
    "            return 0\n",
    "        elif x > y:\n",
    "            return 1\n",
    "        else:\n",
    "            return -1\n",
    "            \n",
    "\n",
    "\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        index = sorted(range(n), key = lambda x: aliceValues[x]+bobValues[x], reverse = True)\n",
    "        cnt = 0\n",
    "        for i in range(n):\n",
    "            if i % 2: cnt -= bobValues[index[i]]\n",
    "            else:   cnt += aliceValues[index[i]]\n",
    "        if cnt > 0: return 1\n",
    "        elif cnt < 0:   return -1\n",
    "        return cnt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        total = list(range(n))\n",
    "        total.sort(key = lambda i:aliceValues[i] + bobValues[i], reverse = True)\n",
    "        # print(total)\n",
    "        x = sum((aliceValues[i] for i in total[::2]))\n",
    "        y = sum(bobValues[i] for i in total[1::2])\n",
    "        # print(x, y)\n",
    "        if x == y:\n",
    "            return 0\n",
    "        elif x > y:\n",
    "            return 1\n",
    "        else:\n",
    "            return -1\n",
    "            \n",
    "\n",
    "\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        total = list(range(n))\n",
    "        total.sort(key = lambda i:aliceValues[i] + bobValues[i], reverse = True)\n",
    "        # print(total)\n",
    "        x = sum((aliceValues[i] for i in total[::2]))\n",
    "        y = sum(bobValues[i] for i in total[1::2])\n",
    "        # print(x, y)\n",
    "        if x == y:\n",
    "            return 0\n",
    "        elif x > y:\n",
    "            return 1\n",
    "        else:\n",
    "            return -1\n",
    "            \n",
    "\n",
    "\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        total = list(range(n))\n",
    "        total.sort(key = lambda i:aliceValues[i] + bobValues[i], reverse = True)\n",
    "        # print(total)\n",
    "        x = sum((aliceValues[i] for i in total[::2]))\n",
    "        y = sum(bobValues[i] for i in total[1::2])\n",
    "        # print(x, y)\n",
    "        if x == y:\n",
    "            return 0\n",
    "        elif x > y:\n",
    "            return 1\n",
    "        else:\n",
    "            return -1\n",
    "            \n",
    "\n",
    "\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        total = list(range(n))\n",
    "        total.sort(key = lambda i:aliceValues[i] + bobValues[i], reverse = True)\n",
    "        # print(total)\n",
    "        x = sum((aliceValues[i] for i in total[::2]))\n",
    "        y = sum(bobValues[i] for i in total[1::2])\n",
    "        # print(x, y)\n",
    "        if x == y:\n",
    "            return 0\n",
    "        elif x > y:\n",
    "            return 1\n",
    "        else:\n",
    "            return -1\n",
    "            \n",
    "\n",
    "\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        p = sorted(list(range(len(aliceValues))), key = lambda i:aliceValues[i]+bobValues[i], reverse=True)\n",
    "        a = sum(aliceValues[i] for i in p[::2])\n",
    "        b = sum(bobValues[i] for i in p[1::2])\n",
    "        return 1 if a > b else 0 if a == b else -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        arr = [(x + y, x) for x, y in zip(aliceValues, bobValues)]\n",
    "        arr.sort()\n",
    "        n = len(arr)\n",
    "        alice_sum = bob_sum = 0\n",
    "        flag = True\n",
    "        for i in range(n - 1, -1, -1):\n",
    "            if flag:\n",
    "                alice_sum += arr[i][1]\n",
    "            else:\n",
    "                bob_sum += (arr[i][0] - arr[i][1])\n",
    "            flag = not flag\n",
    "        if alice_sum > bob_sum:\n",
    "            return 1\n",
    "        elif alice_sum == bob_sum:\n",
    "            return 0\n",
    "        else:\n",
    "            return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        stones = [(aliceValues[i] + bobValues[i],aliceValues[i],bobValues[i]) for i in range(n)]\n",
    "        stones.sort(reverse = True)\n",
    "\n",
    "        alice = 0\n",
    "        bob = 0\n",
    "\n",
    "        for i,t in enumerate(stones):\n",
    "            if i%2 == 0:\n",
    "                alice += t[1]\n",
    "            else:\n",
    "                bob += t[2]\n",
    "            \n",
    "        if alice == bob:\n",
    "            return 0\n",
    "        elif alice > bob:\n",
    "            return 1\n",
    "        else:\n",
    "            return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from typing import List\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        total_values = [(aliceValues[i] + bobValues[i], aliceValues[i], bobValues[i]) for i in range(n)]\n",
    "        \n",
    "        # 按照石头对两人总价值的贡献进行排序\n",
    "        total_values.sort(reverse=True)\n",
    "        \n",
    "        alice_score, bob_score = 0, 0\n",
    "        \n",
    "        for i in range(n):\n",
    "            if i % 2 == 0:  # Alice's turn\n",
    "                alice_score += total_values[i][1]\n",
    "            else:  # Bob's turn\n",
    "                bob_score += total_values[i][2]\n",
    "                \n",
    "        if alice_score > bob_score:\n",
    "            return 1\n",
    "        elif alice_score < bob_score:\n",
    "            return -1\n",
    "        else:\n",
    "            return 0\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "\n",
    "        # 按两人总分排序石子\n",
    "        lst = [(aliceValues[i], bobValues[i]) for i in range(n)]\n",
    "        lst.sort(key=lambda x: x[0] + x[1], reverse=True)\n",
    "\n",
    "        alice, bob = 0, 0\n",
    "        for i in range(len(lst)):\n",
    "            if i % 2 == 0:\n",
    "                alice += lst[i][0]\n",
    "            else:\n",
    "                bob += lst[i][1]\n",
    "\n",
    "        if alice > bob:\n",
    "            return 1\n",
    "        elif alice < bob:\n",
    "            return -1\n",
    "        else:\n",
    "            return 0\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        # 排序，两种价值加起来越大的，越靠前\n",
    "        n = len(aliceValues)\n",
    "        rec = [(aliceValues[i], bobValues[i]) for i in range(n)]\n",
    "        rec.sort(key=lambda x:(x[0]+x[1]), reverse=True)\n",
    "        first,second = 0,0\n",
    "        for i in range(n):\n",
    "            if i%2==0:\n",
    "                first += rec[i][0]\n",
    "            else:\n",
    "                second += rec[i][1]\n",
    "        if first==second:\n",
    "            return 0\n",
    "        elif first>second:\n",
    "            return 1\n",
    "        return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        values = sorted(((i, j) for i,j in zip(aliceValues, bobValues)), key = sum, reverse = True)\n",
    "        a = 0\n",
    "        b = 0\n",
    "        for i in range(len(values)):\n",
    "            if i&1:\n",
    "                b += values[i][1]\n",
    "            else:\n",
    "                a += values[i][0]\n",
    "        if a > b:\n",
    "            return 1\n",
    "        elif a == b:\n",
    "            return 0\n",
    "        else:\n",
    "            return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        a = sorted(zip(aliceValues, bobValues), key=lambda t: t[0] + t[1], reverse=True)\n",
    "        f = lambda i: sum(a[t][i] for t in range(i, len(a), 2))\n",
    "        a = f(0) - f(1)\n",
    "        return a and (1 if a > 0 else -1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        rec = [(aliceValues[i], bobValues[i]) for i in range(n)]\n",
    "        rec.sort(key=lambda x:(x[0]+x[1]), reverse=True)\n",
    "        first = sum([rec[i][0] for i in range(n) if i%2==0])\n",
    "        secend = sum([rec[i][1] for i in range(n) if i%2!=0])\n",
    "        if first==secend:\n",
    "            return 0\n",
    "        elif first>secend:\n",
    "            return 1\n",
    "        return -1\n",
    "        pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        values = [(aliceValues[i] ,bobValues[i]) for i in range(len(aliceValues))]\n",
    "        n = len(aliceValues)\n",
    "        used = [False] * n\n",
    "        values.sort(key=lambda x:(x[0]+x[1]), reverse=True)\n",
    "        A, B = 0, 0\n",
    "        for i in range(n):\n",
    "            if not i % 2 :\n",
    "                A += values[i][0]\n",
    "            else:\n",
    "                B += values[i][1]\n",
    "        if A > B: \n",
    "            return 1\n",
    "        elif A < B:\n",
    "            return -1\n",
    "        else:\n",
    "            return 0               \n",
    "            \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        values = [(aliceValues[i] + bobValues[i], i) for i in range(len(aliceValues))]\n",
    "        values.sort(reverse=True)\n",
    "        alice = 0\n",
    "        bob = 0\n",
    "        cur = 0\n",
    "        for val, i in values:\n",
    "            if cur % 2 == 0:\n",
    "                alice += aliceValues[i]\n",
    "            else:\n",
    "                bob += bobValues[i]\n",
    "            cur += 1\n",
    "        if alice > bob:\n",
    "            return 1\n",
    "        elif alice == bob:\n",
    "            return 0\n",
    "        else:\n",
    "            return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        q = []\n",
    "        n = len(aliceValues)\n",
    "        for i in range(n):\n",
    "            q.append((aliceValues[i] + bobValues[i], i))\n",
    "        q.sort(reverse=True)\n",
    "        cur = 0\n",
    "        a = b = 0\n",
    "        while cur < n:\n",
    "            if cur % 2 == 0:\n",
    "                a += aliceValues[q[cur][1]]\n",
    "            else:\n",
    "                b += bobValues[q[cur][1]]\n",
    "            cur += 1\n",
    "        return 1 if a > b else -1 if a < b else 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        s = [[a + b, a, b] for a, b in zip(aliceValues, bobValues)]\n",
    "        s.sort(reverse=True)\n",
    "        s1, s2 = sum(x[1] for x in s[::2]), sum(x[2] for x in s[1::2])\n",
    "        if s1 > s2:\n",
    "            return 1\n",
    "        elif s1 == s2:\n",
    "            return 0\n",
    "        return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int: \n",
    "        n = len(aliceValues)\n",
    "        stones = [(aliceValues[i] + bobValues[i], i) for i in range(n)]\n",
    "        stones.sort(reverse=True)\n",
    "        a_score, b_score = 0, 0\n",
    "        for i in range(n):\n",
    "            if i % 2 == 0:\n",
    "                a_score += aliceValues[stones[i][1]]\n",
    "            else:\n",
    "                b_score += bobValues[stones[i][1]]\n",
    "        if a_score > b_score:\n",
    "            return 1\n",
    "        elif a_score < b_score:\n",
    "            return -1\n",
    "        else:\n",
    "            return 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)           \n",
    "        sums = [(aliceValues[i] + bobValues[i], i) for i in range(n)]\n",
    "        sums.sort(reverse = True)\n",
    "        sums_alice, sums_bob = 0, 0\n",
    "        for i in range(n):\n",
    "            if i % 2 == 0:\n",
    "                sums_alice += aliceValues[sums[i][-1]]\n",
    "            else:\n",
    "                sums_bob += bobValues[sums[i][-1]]\n",
    "        ret = 1\n",
    "        if sums_bob == sums_alice:\n",
    "            ret = 0\n",
    "        elif sums_bob > sums_alice:\n",
    "            ret = -1\n",
    "        return ret"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\r\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\r\n",
    "        # 一个石子要么alice拿，要么bob拿 \r\n",
    "        # 所以 贡献为 aliceValues[i] - bobValues[i]\r\n",
    "        # alice 可以拿 (n + 1) // 2 个石子 \r\n",
    "        # \r\n",
    "        n = len(aliceValues)\r\n",
    "        v = [(x + y, i) for i, (x, y) in enumerate(zip(aliceValues, bobValues))]\r\n",
    "        v.sort(reverse=True)\r\n",
    "        \r\n",
    "        alice, bob = 0, 0\r\n",
    "        for i in range(n):\r\n",
    "            if i % 2 == 0:\r\n",
    "                alice += aliceValues[v[i][1]] \r\n",
    "            else:\r\n",
    "                bob += bobValues[v[i][1]]\r\n",
    "        if alice > bob:\r\n",
    "            return 1 \r\n",
    "        elif alice == bob:\r\n",
    "            return 0 \r\n",
    "        return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        arr = [None] * n\n",
    "        alice = bob = 0\n",
    "        for i in range(n):\n",
    "            arr[i] = (aliceValues[i] + bobValues[i], aliceValues[i], bobValues[i])\n",
    "        arr.sort(key = lambda x: (-x[0]))\n",
    "        for i in range(n):\n",
    "            if i % 2 == 0:\n",
    "                alice += arr[i][1]\n",
    "            else:\n",
    "                bob += arr[i][2]\n",
    "        if bob == alice: return 0\n",
    "        return 1 if alice > bob else -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        t = sorted(zip(aliceValues, bobValues), key = lambda x: -x[0]-x[1])\n",
    "        d = 0\n",
    "        for i in range(len(t)):\n",
    "            if ~i & 1: d += t[i][0]\n",
    "            else: d -= t[i][1]\n",
    "        if d == 0: return 0\n",
    "        return 1 if d > 0 else -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "'''\n",
    "将两组石头的价值合并，每次取价值最大的那一组\n",
    "'''\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        n = len(aliceValues)\n",
    "        newValues = [a+b for a, b in zip(aliceValues, bobValues)]\n",
    "        newValues = [(i, x) for i, x in enumerate(newValues)]\n",
    "        newValues.sort(key=lambda x: x[1], reverse=True)\n",
    "        s1, s2 = 0, 0\n",
    "        for i in range(n):\n",
    "            if i % 2 == 0:\n",
    "                # 偶数下标alice来取\n",
    "                s1 += aliceValues[newValues[i][0]]\n",
    "            else:\n",
    "                # 奇数下标bob来取\n",
    "                s2 += bobValues[newValues[i][0]]\n",
    "        \n",
    "        if s1 > s2: return 1\n",
    "        elif s1 == s2: return 0\n",
    "        else: return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        values = [x + y for x, y in zip(aliceValues,bobValues)]\n",
    "        Index = [i[0] for i in sorted(enumerate(values), key=lambda x:x[1],reverse=True)]\n",
    "        aliWin = 0\n",
    "        for i in Index[::2]:\n",
    "            aliWin += aliceValues[i]\n",
    "        for i in Index[1::2]:\n",
    "            aliWin -= bobValues[i]\n",
    "\n",
    "        if aliWin>0:\n",
    "            return 1\n",
    "        elif aliWin<0:\n",
    "            return -1\n",
    "        else:\n",
    "            return 0\n",
    "\n",
    "            \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        real_val = [i+j for i, j in zip(aliceValues, bobValues)]\n",
    "        idx = sorted(zip(real_val, list(range(len(aliceValues)))), reverse=True)\n",
    "        alice, bob = sum(aliceValues[i] for v, i in idx[::2]), sum(bobValues[i] for v, i in idx[1::2])\n",
    "        if alice > bob:\n",
    "            return 1 \n",
    "        elif alice == bob:\n",
    "            return 0 \n",
    "        else:\n",
    "            return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        dic = collections.defaultdict(int)\n",
    "        for i in range(len(aliceValues)):\n",
    "            dic[i]+=aliceValues[i]+bobValues[i]\n",
    "        tmp = sorted(dic)\n",
    "        tmp.sort(key = lambda x:dic[x],reverse=True)\n",
    "        res = 0\n",
    "        for i in range(len(tmp)):\n",
    "            if i%2==0:\n",
    "                res+=aliceValues[tmp[i]]\n",
    "            else:\n",
    "                res-=bobValues[tmp[i]]\n",
    "        if res>0:\n",
    "            return 1\n",
    "        elif res==0:\n",
    "            return 0\n",
    "        return -1\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        dic = collections.defaultdict(int)\n",
    "        for i in range(len(aliceValues)):\n",
    "            dic[i]+=aliceValues[i]+bobValues[i]\n",
    "        tmp = sorted(dic)\n",
    "        tmp.sort(key = lambda x:dic[x],reverse=True)\n",
    "        res = 0\n",
    "        for i in range(len(tmp)):\n",
    "            if i%2==0:\n",
    "                res+=aliceValues[tmp[i]]\n",
    "            else:\n",
    "                res-=bobValues[tmp[i]]\n",
    "        if res>0:\n",
    "            return 1\n",
    "        elif res==0:\n",
    "            return 0\n",
    "        return -1\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        dic = collections.defaultdict(int)\n",
    "        for i in range(len(aliceValues)):\n",
    "            dic[i]+=aliceValues[i]+bobValues[i]\n",
    "        tmp = sorted(dic)\n",
    "        tmp.sort(key = lambda x:dic[x],reverse=True)\n",
    "        res = 0\n",
    "        for i in range(len(tmp)):\n",
    "            if i%2==0:\n",
    "                res+=aliceValues[tmp[i]]\n",
    "            else:\n",
    "                res-=bobValues[tmp[i]]\n",
    "        if res>0:\n",
    "            return 1\n",
    "        elif res==0:\n",
    "            return 0\n",
    "        return -1\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        dic = collections.defaultdict(int)\n",
    "        for i in range(len(aliceValues)):\n",
    "            dic[i]+=aliceValues[i]+bobValues[i]\n",
    "        tmp = sorted(dic)\n",
    "        tmp.sort(key = lambda x:dic[x],reverse=True)\n",
    "        res = 0\n",
    "        for i in range(len(tmp)):\n",
    "            if i%2==0:\n",
    "                res+=aliceValues[tmp[i]]\n",
    "            else:\n",
    "                res-=bobValues[tmp[i]]\n",
    "        if res>0:\n",
    "            return 1\n",
    "        elif res==0:\n",
    "            return 0\n",
    "        return -1\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        tmp = []\n",
    "        for i in range(len(aliceValues)):\n",
    "            t = aliceValues[i] + bobValues[i]\n",
    "            tmp.append([i,t])\n",
    "        tmp.sort(key=lambda x : x[1],reverse=True)\n",
    "        a,b = 0,0\n",
    "        for i in range(len(tmp)):\n",
    "            if i%2==0:\n",
    "                a += aliceValues[tmp[i][0]]\n",
    "            else:\n",
    "                b += bobValues[tmp[i][0]]\n",
    "        if a>b:\n",
    "            return 1\n",
    "        elif a<b:\n",
    "            return -1\n",
    "        else:\n",
    "            return 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        sum = []\n",
    "        for i, (a,b) in enumerate(zip(aliceValues, bobValues)):\n",
    "            sum.append([i, a+b])\n",
    "        sum.sort(key=lambda x: x[1], reverse=True)\n",
    "        flag, valA, valB = True, 0, 0\n",
    "        for x in sum:\n",
    "            if flag:\n",
    "                valA += aliceValues[x[0]]\n",
    "            else:\n",
    "                valB += bobValues[x[0]]\n",
    "            flag = not flag\n",
    "        return 1 if valA > valB else (0 if valA == valB else -1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        data = [[aliceValues[i] + bobValues[i], i] for i in range(len(aliceValues))]\n",
    "        data.sort(key=lambda x: x[0], reverse=True)\n",
    "        a = sum(aliceValues[data[i][1]] for i in range(0, len(data), 2))\n",
    "        b = sum(bobValues[data[i][1]] for i in range(1, len(data), 2))\n",
    "        return 0 if a == b else (1 if a > b else -1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        data = [[aliceValues[i] + bobValues[i], i] for i in range(len(aliceValues))]\n",
    "        data.sort(key=lambda x: x[0], reverse=True)\n",
    "        a = sum(aliceValues[data[i][1]] for i in range(0, len(data), 2))\n",
    "        b = sum(bobValues[data[i][1]] for i in range(1, len(data), 2))\n",
    "        return 0 if a == b else (1 if a > b else -1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        data = [[aliceValues[i] + bobValues[i], i] for i in range(len(aliceValues))]\n",
    "        data.sort(key=lambda x: x[0], reverse=True)\n",
    "        a = sum(aliceValues[data[i][1]] for i in range(0, len(data), 2))\n",
    "        b = sum(bobValues[data[i][1]] for i in range(1, len(data), 2))\n",
    "        return 0 if a == b else (1 if a > b else -1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        data = [[aliceValues[i] + bobValues[i], i] for i in range(len(aliceValues))]\n",
    "        data.sort(key=lambda x: x[0], reverse=True)\n",
    "        a = sum(aliceValues[data[i][1]] for i in range(0, len(data), 2))\n",
    "        b = sum(bobValues[data[i][1]] for i in range(1, len(data), 2))\n",
    "        return 0 if a == b else (1 if a > b else -1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        value = []\n",
    "        for i in range(len(aliceValues)):\n",
    "            value.append([aliceValues[i]+bobValues[i],i])\n",
    "        value.sort(key=lambda x: x[0],reverse=True)\n",
    "        # print(value)\n",
    "        scoreA = 0\n",
    "        scoreB = 0\n",
    "        for i in range(len(aliceValues)):\n",
    "            if i%2 == 0:\n",
    "                scoreA += aliceValues[value[i][1]]\n",
    "            else:\n",
    "                scoreB += bobValues[value[i][1]]\n",
    "        if scoreA > scoreB:\n",
    "            return 1\n",
    "        elif scoreA < scoreB:\n",
    "            return -1\n",
    "        else:\n",
    "            return 0\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        data = [[aliceValues[i] + bobValues[i], i] for i in range(len(aliceValues))]\n",
    "        data.sort(key=lambda x: x[0], reverse=True)\n",
    "        a = sum(aliceValues[data[i][1]] for i in range(0, len(data), 2))\n",
    "        b = sum(bobValues[data[i][1]] for i in range(1, len(data), 2))\n",
    "        return 0 if a == b else (1 if a > b else -1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        arr = []\n",
    "        for i, (a, b) in enumerate(zip(aliceValues, bobValues)):\n",
    "            arr.append((a + b, i))\n",
    "        arr.sort(reverse = True)\n",
    "        print(arr)\n",
    "        ans = 0\n",
    "        for i, (x, p) in enumerate(arr):\n",
    "            if i & 1:\n",
    "                ans -= bobValues[p]\n",
    "            else:\n",
    "                ans += aliceValues[p]\n",
    "        if ans > 0: return 1\n",
    "        if ans < 0: return -1\n",
    "        return 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        v = [(a+b, i) for a,b,i in zip(aliceValues, bobValues,range(len(aliceValues)))]\n",
    "        v.sort(key=lambda x:-x[0])\n",
    "        aval = bval = 0\n",
    "        for i in range(0, len(aliceValues), 2):\n",
    "            aval += aliceValues[v[i][1]]\n",
    "        for i in range(1, len(aliceValues), 2):\n",
    "            bval += bobValues[v[i][1]]\n",
    "        if aval > bval:\n",
    "            return 1\n",
    "        elif aval < bval:\n",
    "            return -1\n",
    "        return 0\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        s=[(aliceValues[i]+bobValues[i],i) for i in range(len(aliceValues))]\n",
    "        s=sorted(s,key=lambda x:-x[0])\n",
    "        s1=s[0::2]\n",
    "        s2=s[1::2]\n",
    "        A=B=0\n",
    "        for x in s1:\n",
    "            A+=aliceValues[x[1]]\n",
    "        for x in s2:\n",
    "            B+=bobValues[x[1]]\n",
    "        if A>B:\n",
    "            return 1\n",
    "        elif A==B:\n",
    "            return 0\n",
    "        else:\n",
    "            return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        s=[(aliceValues[i]+bobValues[i],i) for i in range(len(aliceValues))]\n",
    "        s=sorted(s,key=lambda x:-x[0])\n",
    "        s1=s[0::2]\n",
    "        s2=s[1::2]\n",
    "        A=B=0\n",
    "        for x in s1:\n",
    "            A+=aliceValues[x[1]]\n",
    "        for x in s2:\n",
    "            B+=bobValues[x[1]]\n",
    "        if A>B:\n",
    "            return 1\n",
    "        elif A==B:\n",
    "            return 0\n",
    "        else:\n",
    "            return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        # 选择当前石子差值最大的（负数最大）或者整数最大\n",
    "\n",
    "        diff_alice = []\n",
    "        n = len(aliceValues)\n",
    "        for i in range(n):\n",
    "            diff_alice.append(abs(aliceValues[i]+bobValues[i]))\n",
    "        \n",
    "        used_lst = [False] * n\n",
    "        \n",
    "        diff_alice = [(i, item) for i, item in enumerate(diff_alice)]\n",
    "        diff_alice = sorted(diff_alice, key=lambda x: -x[1])\n",
    "\n",
    "        print(diff_alice)\n",
    "        aliceVal, bobVal = 0, 0\n",
    "        for idx, info in enumerate(diff_alice):\n",
    "            i, diff = info\n",
    "            if idx & 1 == 0:\n",
    "                # alice\n",
    "                aliceVal += aliceValues[i]\n",
    "            else:\n",
    "                # bob\n",
    "                bobVal += bobValues[i]\n",
    "\n",
    "        if aliceVal > bobVal:\n",
    "            return 1\n",
    "        elif aliceVal == bobVal:\n",
    "            return 0\n",
    "        else:\n",
    "            return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        # 选择当前石子差值最大的（负数最大）或者整数最大\n",
    "\n",
    "        diff_alice = []\n",
    "        n = len(aliceValues)\n",
    "        for i in range(n):\n",
    "            diff_alice.append(abs(aliceValues[i]+bobValues[i]))\n",
    "        \n",
    "        used_lst = [False] * n\n",
    "        \n",
    "        diff_alice = [(i, item) for i, item in enumerate(diff_alice)]\n",
    "        diff_alice = sorted(diff_alice, key=lambda x: -x[1])\n",
    "\n",
    "        print(diff_alice)\n",
    "        aliceVal, bobVal = 0, 0\n",
    "        for idx, info in enumerate(diff_alice):\n",
    "            i, diff = info\n",
    "            if idx & 1 == 0:\n",
    "                # alice\n",
    "                aliceVal += aliceValues[i]\n",
    "            else:\n",
    "                # bob\n",
    "                bobVal += bobValues[i]\n",
    "\n",
    "        if aliceVal > bobVal:\n",
    "            return 1\n",
    "        elif aliceVal == bobVal:\n",
    "            return 0\n",
    "        else:\n",
    "            return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:\n",
    "        # 选择当前石子差值最大的（负数最大）或者整数最大\n",
    "\n",
    "        diff_alice = []\n",
    "        n = len(aliceValues)\n",
    "        for i in range(n):\n",
    "            diff_alice.append(abs(aliceValues[i]+bobValues[i]))\n",
    "        \n",
    "        used_lst = [False] * n\n",
    "        \n",
    "        diff_alice = [(i, item) for i, item in enumerate(diff_alice)]\n",
    "        diff_alice = sorted(diff_alice, key=lambda x: -x[1])\n",
    "\n",
    "        print(diff_alice)\n",
    "        aliceVal, bobVal = 0, 0\n",
    "        for idx, info in enumerate(diff_alice):\n",
    "            i, diff = info\n",
    "            if idx & 1 == 0:\n",
    "                # alice\n",
    "                aliceVal += aliceValues[i]\n",
    "            else:\n",
    "                # bob\n",
    "                bobVal += bobValues[i]\n",
    "\n",
    "        if aliceVal > bobVal:\n",
    "            return 1\n",
    "        elif aliceVal == bobVal:\n",
    "            return 0\n",
    "        else:\n",
    "            return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from functools import cache\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        presum = [0]\n",
    "        for s in stones:\n",
    "            presum.append(presum[-1] + s)\n",
    "        n = len(stones)\n",
    "        dp = [0]*n\n",
    "        for l in range(1, n):\n",
    "            ndp = []\n",
    "            for i in range(n - l):\n",
    "\n",
    "                ndp.append(max(presum[i + l] - presum[i] - dp[i], presum[i+l+1] - presum[i+1] - dp[i+1]))\n",
    "            dp = ndp\n",
    "        return ndp[0]\n",
    "\n",
    "        # def dfs(l, r):\n",
    "        #     if l == r:\n",
    "        #         return 0\n",
    "        #     return max(presum[r] - presum[l] - dfs(l, r - 1), presum[r+1] - presum[l+1] - dfs(l+1, r))\n",
    "        # return dfs(0, len(stones) - 1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "        if not n & 1:\n",
    "            for i in range(n):\n",
    "                dp[i][i] = stones[i]\n",
    "        for L in range(2, n + 1):\n",
    "            for i in range(n - L + 1):\n",
    "                j = i + L - 1\n",
    "                if L & 1 == n & 1:\n",
    "                    dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])\n",
    "                else:\n",
    "                    dp[i][j] = min(dp[i + 1][j] + stones[i], dp[i][j - 1] + stones[j])\n",
    "        return dp[0][-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        f = [[0] * n for _ in range(n)]\n",
    "        if n & 1 == 0:\n",
    "            for i in range(n):\n",
    "                f[i][i] = stones[i]\n",
    "        for L in range(2, n + 1):\n",
    "            for i in range(n - L + 1):\n",
    "                j = i + L - 1\n",
    "                if L & 1 == n & 1:\n",
    "                    f[i][j] = max(f[i + 1][j], f[i][j - 1])\n",
    "                else:\n",
    "                    f[i][j] = min(f[i + 1][j] + stones[i], f[i][j - 1] + stones[j])\n",
    "        return f[0][-1]\n",
    "\n",
    "        # s = list(accumulate(stones, initial=0))\n",
    "        # n = len(stones)\n",
    "        # f = [[0] * n for _ in range(n)]\n",
    "        # for L in range(2, n + 1):\n",
    "        #     i, j = 0, L - 1\n",
    "        #     while j < n:\n",
    "        #         f[i][j] = max(s[j + 1] - s[i + 1] - f[i + 1][j], s[j] - s[i] - f[i][j - 1])\n",
    "        #         i += 1\n",
    "        #         j += 1\n",
    "        # return f[0][n - 1]\n",
    "\n",
    "        # s = list(accumulate(stones, initial=0))\n",
    "        # @cache\n",
    "        # def dfs(i, j):\n",
    "        #     if i == j:\n",
    "        #         return 0\n",
    "        #     return max(s[j + 1] - s[i + 1] - dfs(i + 1, j), s[j] - s[i] - dfs(i, j - 1))\n",
    "        # res = dfs(0, len(stones) - 1)\n",
    "        # del dfs\n",
    "        # return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "\n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "        # 长度偶数\n",
    "        if not  n & 1:\n",
    "            for i in range(n):\n",
    "                dp[i][i] = stones[i]\n",
    "        \n",
    "        for L in range(2, n+1):\n",
    "            for i in range(n - L +1):\n",
    "                j = i + L - 1\n",
    "\n",
    "                if L & 1 == n & 1:\n",
    "                    dp[i][j] = max(dp[i][j-1], dp[i+1][j])\n",
    "                else:\n",
    "                    dp[i][j] = min(dp[i+1][j] + stones[i], dp[i][j-1] + stones[j])\n",
    "        return dp[0][-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        t = n & 1\n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "        if t == 0:\n",
    "            for i in range(n):\n",
    "                dp[i][i] = stones[i]\n",
    "        for L in range(2, n + 1):\n",
    "            for i in range(n - L + 1):\n",
    "                j = i + L - 1\n",
    "                if L & 1 == t:\n",
    "                    dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])\n",
    "                else:\n",
    "                    dp[i][j] = min(dp[i + 1][j] + stones[i], dp[i][j - 1] + stones[j])\n",
    "        return dp[0][-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "        if not n & 1:\n",
    "            for i in range(n):\n",
    "                dp[i][i] = stones[i]\n",
    "        for L in range(2, n + 1):\n",
    "            for i in range(n - L + 1):\n",
    "                j = i + L - 1\n",
    "                if L & 1 == n & 1:\n",
    "                    dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])\n",
    "                else:\n",
    "                    dp[i][j] = min(dp[i + 1][j] + stones[i], dp[i][j - 1] + stones[j])\n",
    "        return dp[0][-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "        if not n & 1:\n",
    "            for i in range(n):\n",
    "                dp[i][i] = stones[i]\n",
    "        for L in range(2, n + 1):\n",
    "            for i in range(n - L + 1):\n",
    "                j = i + L - 1\n",
    "                if L & 1 == n & 1:\n",
    "                    dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])\n",
    "                else:\n",
    "                    dp[i][j] = min(dp[i + 1][j] + stones[i], dp[i][j - 1] + stones[j])\n",
    "        return dp[0][-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        N=len(stones)\n",
    "        dp=[[0 for m in range(N)] for n in range(N)]\n",
    "        if N%2==1:\n",
    "            for k in range(N):\n",
    "               dp[k][k]=0\n",
    "        else:\n",
    "            for k in range(N):\n",
    "                dp[k][k]=stones[k]\n",
    "\n",
    "        for p in range(1,N):\n",
    "            for q in range(N-p):\n",
    "                i=q\n",
    "                j=p+q\n",
    "                if (j-i+1)%2==N%2:\n",
    "                    dp[i][j]=max(dp[i+1][j],dp[i][j-1])\n",
    "                else:\n",
    "                    dp[i][j]=min(stones[i]+dp[i+1][j],stones[j]+dp[i][j-1])\n",
    "        return dp[0][N-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        dp = [[0 for _ in range(n)] for _ in range(n)]\n",
    "        if n %2 == 0:\n",
    "            for i in range(n):\n",
    "                dp[i][i] = stones[i]\n",
    "\n",
    "        for l in range(2, n+1):\n",
    "            for i in range(n-l+1):\n",
    "                j = i + l -1\n",
    "                if l & 1 == n & 1:\n",
    "                    dp[i][j] = max(dp[i+1][j], dp[i][j-1])\n",
    "                else:\n",
    "                    dp[i][j] = min(dp[i+1][j] + stones[i], dp[i][j-1] + stones[j])\n",
    "        return dp[0][-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        N=len(stones)\n",
    "        dp=[[0 for m in range(N)] for n in range(N)]\n",
    "        if N%2==1:\n",
    "            for k in range(N):\n",
    "               dp[k][k]=0\n",
    "        else:\n",
    "            for k in range(N):\n",
    "                dp[k][k]=stones[k]\n",
    "\n",
    "        for p in range(1,N):\n",
    "            for q in range(N-p):\n",
    "                i=q\n",
    "                j=p+q\n",
    "                if (j-i+1)%2==N%2:\n",
    "                    dp[i][j]=max(dp[i+1][j],dp[i][j-1])\n",
    "                else:\n",
    "                    dp[i][j]=min(stones[i]+dp[i+1][j],stones[j]+dp[i][j-1])\n",
    "        return dp[0][N-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        N=len(stones)\n",
    "        dp=[[0 for m in range(N)] for n in range(N)]\n",
    "        if N%2==1:\n",
    "            for k in range(N):\n",
    "               dp[k][k]=0\n",
    "        else:\n",
    "            for k in range(N):\n",
    "                dp[k][k]=stones[k]\n",
    "\n",
    "        for p in range(1,N):\n",
    "            for q in range(N-p):\n",
    "                i=q\n",
    "                j=p+q\n",
    "                if (j-i+1)%2==N%2:\n",
    "                    dp[i][j]=max(dp[i+1][j],dp[i][j-1])\n",
    "                else:\n",
    "                    dp[i][j]=min(stones[i]+dp[i+1][j],stones[j]+dp[i][j-1])\n",
    "        return dp[0][N-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        N=len(stones)\n",
    "        dp=[[0 for m in range(N)] for n in range(N)]\n",
    "        if N%2==1:\n",
    "            for k in range(N):\n",
    "               dp[k][k]=0\n",
    "        else:\n",
    "            for k in range(N):\n",
    "                dp[k][k]=stones[k]\n",
    "\n",
    "        for p in range(1,N):\n",
    "            for q in range(N-p):\n",
    "                i=q\n",
    "                j=p+q\n",
    "                if (j-i+1)%2==N%2:\n",
    "                    dp[i][j]=max(dp[i+1][j],dp[i][j-1])\n",
    "                else:\n",
    "                    dp[i][j]=min(stones[i]+dp[i+1][j],stones[j]+dp[i][j-1])\n",
    "        return dp[0][N-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        N=len(stones)\n",
    "        dp=[[0 for m in range(N)] for n in range(N)]\n",
    "        if N%2==1:\n",
    "            for k in range(N):\n",
    "               dp[k][k]=0\n",
    "        else:\n",
    "            for k in range(N):\n",
    "                dp[k][k]=stones[k]\n",
    "\n",
    "        for p in range(1,N):\n",
    "            for q in range(N-p):\n",
    "                i=q\n",
    "                j=p+q\n",
    "                if (j-i+1)%2==N%2:\n",
    "                    dp[i][j]=max(dp[i+1][j],dp[i][j-1])\n",
    "                else:\n",
    "                    dp[i][j]=min(stones[i]+dp[i+1][j],stones[j]+dp[i][j-1])\n",
    "        return dp[0][N-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        N=len(stones)\n",
    "        dp=[[0 for m in range(N)] for n in range(N)]\n",
    "        if N%2==1:\n",
    "            for k in range(N):\n",
    "               dp[k][k]=0\n",
    "        else:\n",
    "            for k in range(N):\n",
    "                dp[k][k]=stones[k]\n",
    "\n",
    "        for p in range(1,N):\n",
    "            for q in range(N-p):\n",
    "                i=q\n",
    "                j=p+q\n",
    "                if (j-i+1)%2==N%2:\n",
    "                    dp[i][j]=max(dp[i+1][j],dp[i][j-1])\n",
    "                else:\n",
    "                    dp[i][j]=min(stones[i]+dp[i+1][j],stones[j]+dp[i][j-1])\n",
    "        return dp[0][N-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "\n",
    "        # 计算前缀和数列\n",
    "        prefix = [0]\n",
    "        now = 0\n",
    "        for s in stones:\n",
    "            now += s\n",
    "            prefix.append(now)\n",
    "\n",
    "        # print(\"前缀和:\", prefix)\n",
    "\n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "\n",
    "        for l in range(1, n):\n",
    "            for i in range(n - l):\n",
    "                j = i + l\n",
    "\n",
    "                # 当剩下2个石头时\n",
    "                if l == 1:\n",
    "                    dp[i][j] = max(stones[i], stones[j])\n",
    "\n",
    "                # 当剩下3个及以上的石头时\n",
    "                else:\n",
    "                  \n",
    "                    dp[i][j] = max((prefix[j + 1] - prefix[i + 1]) - dp[i + 1][j],  \n",
    "                                   (prefix[j] - prefix[i]) - dp[i][j - 1])  \n",
    "\n",
    "        return dp[0][-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        pres = list(accumulate(stones, initial=0))\n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "\n",
    "        for i in range(n - 1, -1, -1):\n",
    "            for j in range(i + 1, n):\n",
    "                dp[i][j] = max(pres[j + 1] - pres[i + 1] - dp[i + 1][j], pres[j] - pres[i] - dp[i][j - 1])\n",
    "\n",
    "        return dp[0][n - 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        presum=[0]*(n+1)\n",
    "        for i in range(1,n+1):\n",
    "            presum[i]=stones[i-1]+presum[i-1]\n",
    "        dp=[[0]*n for _ in range(n)]\n",
    "        for i in range(n-2,-1,-1):\n",
    "            for j in range(i+1,n):\n",
    "                l=presum[j+1]-presum[i+1]\n",
    "                r=presum[j]-presum[i]\n",
    "                dp[i][j]=max(l-dp[i+1][j],r-dp[i][j-1])\n",
    "        return dp[0][n-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        presum = [0] * (n + 1)\n",
    "        for i in range(1, n + 1):\n",
    "            presum[i] = presum[i - 1] + stones[i - 1]\n",
    "\n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "        for i in range(n - 2, -1, -1):\n",
    "            for j in range(i + 1, n):\n",
    "                l = presum[j + 1] - presum[i + 1]\n",
    "                r = presum[j] - presum[i]\n",
    "                dp[i][j] = max(l - dp[i + 1][j], r - dp[i][j - 1])\n",
    "        return dp[0][n - 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        s = list(accumulate(stones, initial=0))\n",
    "        n = len(stones)\n",
    "        f = [[0] * n for _ in range(n)]\n",
    "        for L in range(2, n + 1):\n",
    "            i, j = 0, L - 1\n",
    "            while j < n:\n",
    "                f[i][j] = max(s[j + 1] - s[i + 1] - f[i + 1][j], s[j] - s[i] - f[i][j - 1])\n",
    "                i += 1\n",
    "                j += 1\n",
    "        return f[0][n - 1]\n",
    "\n",
    "        # s = list(accumulate(stones, initial=0))\n",
    "        # @cache\n",
    "        # def dfs(i, j):\n",
    "        #     if i == j:\n",
    "        #         return 0\n",
    "        #     return max(s[j + 1] - s[i + 1] - dfs(i + 1, j), s[j] - s[i] - dfs(i, j - 1))\n",
    "        # res = dfs(0, len(stones) - 1)\n",
    "        # del dfs\n",
    "        # return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        f = [0] * (n + 1)\n",
    "        for i in range(n):\n",
    "            f[i + 1] = f[i] + stones[i]\n",
    "\n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "\n",
    "        for l in range(2, n + 1):\n",
    "            for i in range(n - l + 1):\n",
    "                j = i + l - 1\n",
    "               \n",
    "                dp[i][j] = max(f[j + 1] - f[i + 1] - dp[i + 1][j], f[j] - f[i] - dp[i][j - 1])\n",
    "        return dp[0][n - 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        pres = list(accumulate(stones, initial=0))\n",
    "        # @cache\n",
    "        # def dfs(l, r):\n",
    "        #     if l > r:\n",
    "        #         return 0\n",
    "        #     res = -inf\n",
    "        #     res = max(res, pres[r + 1] - pres[l + 1] - dfs(l + 1, r))\n",
    "        #     res = max(res, pres[r] - pres[l] - dfs(l, r - 1)) \n",
    "        #     return res    \n",
    "        # return dfs(0, n - 1)\n",
    "\n",
    "        dp = [[0] * (n + 1) for _ in range(n + 1)]\n",
    "\n",
    "        for i in range(n - 1, -1, -1):\n",
    "            for j in range(i + 1, n + 1):\n",
    "                dp[i][j] = max(pres[j] - pres[i + 1] - dp[i + 1][j], pres[j - 1] - pres[i] - dp[i][j - 1])\n",
    "\n",
    "        return dp[0][n]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        pres = list(accumulate(stones, initial = 0))\n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "        for L in range(2, n + 1):\n",
    "            for i in range(n - L + 1):\n",
    "                j = i + L - 1\n",
    "                dp[i][j] = max(pres[j + 1] - pres[i + 1] - dp[i + 1][j], pres[j] - pres[i] - dp[i][j - 1])\n",
    "        return dp[0][-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        pre_sum = [0] * (n + 1)\n",
    "        for i in range(n):\n",
    "            pre_sum[i+1] = pre_sum[i] + stones[i]\n",
    "        \n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "        for i in range(n-1, -1, -1):\n",
    "            for j in range(i+1, n):\n",
    "                dp[i][j] = max(pre_sum[j+1] - pre_sum[i+1] - dp[i+1][j], pre_sum[j] - pre_sum[i] - dp[i][j-1])\n",
    "        \n",
    "\n",
    "        return dp[0][-1]\n",
    "\n",
    "            \n",
    "            \n",
    "        \n",
    "            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        s = list(accumulate(stones, initial=0))\n",
    "        n = len(stones)\n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "        for i in range(1, n):\n",
    "            for j in range(n):\n",
    "                k = j + i\n",
    "                if k >= n: break\n",
    "                if j + 1 < n:\n",
    "                    dp[j][k] = max(dp[j][k], s[k + 1] - s[j + 1] - dp[j + 1][k])\n",
    "                if k - 1 >= 0:\n",
    "                    dp[j][k] = max(dp[j][k], s[k] - s[j] - dp[j][k - 1])\n",
    "        return dp[0][n - 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        pre = [0] * (n + 1)\n",
    "        for i in range(n):\n",
    "            pre[i + 1] = pre[i] + stones[i]\n",
    "\n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "        for i in range(n - 1, -1, -1):\n",
    "            for j in range(i + 1, n):\n",
    "                dp[i][j] = max(pre[j + 1] - pre[i + 1] - dp[i + 1]\n",
    "                               [j], pre[j] - pre[i] - dp[i][j - 1])\n",
    "        return dp[0][n - 1]\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        # 先手对后手的净胜分\n",
    "        # @cache\n",
    "        # def dfs(i,j):\n",
    "        #     if i>j:return 0\n",
    "        #     return max(presum[j+1]-presum[i]-stones[i]-dfs(i+1,j),presum[j+1]-presum[i]-stones[j]-dfs(i,j-1))\n",
    "        # presum=list(itertools.accumulate(stones,initial=0))\n",
    "        # n=len(stones)\n",
    "        # res=dfs(0,n-1)\n",
    "        # dfs.cache_clear()\n",
    "        # return res\n",
    "        presum=list(itertools.accumulate(stones,initial=0))\n",
    "        n=len(stones)\n",
    "        f=[[0]*n for _ in range(n)]\n",
    "        # print(f)\n",
    "        # f[i][j]=max(presum[j+1]-presum[i]-stones[i]-f[i+1][j],presum[j+1]-presum[i]-stones[j]-f[i][j-1])\n",
    "        for i in range(n-1,-1,-1):\n",
    "            for j in range(i,n):\n",
    "                if i==j:\n",
    "                    f[i][j]=0\n",
    "                else:\n",
    "                    f[i][j]=max(presum[j+1]-presum[i]-stones[i]-f[i+1][j],presum[j+1]-presum[i]-stones[j]-f[i][j-1])\n",
    "        return f[0][n-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        length = len(stones)\n",
    "        dp = [[0] * length for _ in range(length)]\n",
    "        pre = [0]\n",
    "        for v in stones:\n",
    "            pre.append(pre[-1] + v)\n",
    "        for j in range(1,length):\n",
    "            for i in range(j - 1, -1, -1):\n",
    "                dp[i][j] = max(pre[j + 1] - pre[i + 1] - dp[i + 1][j], pre[j] - pre[i] - dp[i][j-1])\n",
    "        return dp[0][length - 1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from typing import List\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        # 初始化 dp 数组\n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "        # 初始化前缀和数组\n",
    "        prefix_sum = [0]\n",
    "        for stone in stones:\n",
    "            prefix_sum.append(prefix_sum[-1] + stone)\n",
    "        \n",
    "        for length in range(2, n + 1):  # 从小到大考虑所有子数组的长度\n",
    "            for i in range(n - length + 1):  # 计算起始索引\n",
    "                j = i + length - 1  # 计算结束索引\n",
    "                \n",
    "                # 计算子数组 stones[i:j+1] 的和\n",
    "                total = prefix_sum[j + 1] - prefix_sum[i]\n",
    "                \n",
    "                # 选择一个最优方案\n",
    "                dp[i][j] = max(\n",
    "                    total - stones[i] - dp[i+1][j],\n",
    "                    total - stones[j] - dp[i][j-1]\n",
    "                )\n",
    "        \n",
    "        return dp[0][-1]\n",
    "\n",
    "# 测试代码\n",
    "sol = Solution()\n",
    "print(sol.stoneGameVII([5,3,1,4,2]))  # 输出应为 6\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n=len(stones)\n",
    "        if n==1:\n",
    "            return stones[0]\n",
    "        if n==2:\n",
    "            return max(stones)-min(stones)\n",
    "        dp=[[0 for _ in range(n)]for _ in range(n)]\n",
    "        pre=[0]*(n+1)\n",
    "        for i in range(n):\n",
    "            pre[i+1]=pre[i]+stones[i]\n",
    "            #dp[i][i]=stones[i]\n",
    "        for i in range(n-1,-1,-1):\n",
    "            for j in range(i+1,n):\n",
    "                dp[i][j]=max(pre[j+1]-pre[i+1]-dp[i+1][j],pre[j]-pre[i]-dp[i][j-1])\n",
    "        return dp[0][-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        dp = [[0 for _ in range(n)] for _ in range(n)]\n",
    "        presum = [0]\n",
    "        for num in stones:\n",
    "            presum.append(presum[-1] + num)\n",
    "        for i in range(1, n+1):\n",
    "            for j in range(n-i):\n",
    "                dp[j][i+j] = max(presum[i+j+1]-presum[j+1]-dp[j+1][i+j], presum[i+j]-presum[j]-dp[j][i+j-1])\n",
    "        return dp[0][-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "memo = [[0] * (1001) for _ in range(1001)]\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        pres = list(accumulate(stones, initial=0))\n",
    "        \n",
    "        def query(i, j):\n",
    "            return pres[j + 1] - pres[i]\n",
    "        \n",
    "        for i in range(n):\n",
    "            for j in range(n):\n",
    "                memo[i][j] = inf\n",
    "        \n",
    "        def dfs(i, j):\n",
    "            if i > j:\n",
    "                return 0\n",
    "            if memo[i][j] != inf:\n",
    "                return memo[i][j]\n",
    "            cur = (i + n - 1 - j) & 1\n",
    "            # 极大\n",
    "            if cur == 0:\n",
    "                memo[i][j] = max(dfs(i + 1, j) + query(i + 1, j), dfs(i, j - 1) + query(i, j - 1))\n",
    "                return memo[i][j]\n",
    "            else:\n",
    "                memo[i][j] = min(dfs(i + 1, j) - query(i + 1, j), dfs(i, j - 1) - query(i, j - 1))\n",
    "                return memo[i][j]\n",
    "        \n",
    "        return abs(dfs(0, n - 1))\n",
    "            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        if n & 1:\n",
    "            dp = [{} for _ in range(n)]\n",
    "            for i, dic in enumerate(dp):\n",
    "                dic[i] = 0\n",
    "            for i in range(2, n, 2):\n",
    "                for j in range(n-i):\n",
    "                    dp[j][j+i] = max(min(stones[j+1]+dp[j+2][j+i], stones[j+i]+dp[j+1][j+i-1]), min(stones[j]+dp[j+1][j+i-1], stones[j+i-1]+dp[j][j+i-2]))\n",
    "        else:\n",
    "            dp = [{} for _ in range(n-1)]\n",
    "            for i, dic in enumerate(dp):\n",
    "                dic[i+1] = max(stones[i], stones[i+1])\n",
    "            for i in range(3, n, 2):\n",
    "                for j in range(n-i):\n",
    "                    dp[j][j+i] = max(min(stones[j+1]+dp[j+2][j+i], stones[j+i]+dp[j+1][j+i-1]), min(stones[j]+dp[j+1][j+i-1], stones[j+i-1]+dp[j][j+i-2]))\n",
    "        return dp[0][n-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import sys\n",
    "sys.setrecursionlimit(10**7)\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        pre_sum = [0 for _ in range(len(stones) + 1)]\n",
    "\n",
    "        for i in range(len(stones)):\n",
    "            pre_sum[i + 1] = pre_sum[i] + stones[i]\n",
    "        \n",
    "        #dp[i][j] = max(pre_sum[j + 1] - pre_sum[i] - dp[i + 1][j],  )\n",
    "        #.              pre_sum[j ] - pre_sum[i + 1] - dp[i ][j - 1]\n",
    "\n",
    "        dp = [[float('-inf') for _ in range(len(stones))] for _ in range(len(stones))]\n",
    "        for i in range(len(stones) - 1, -1, -1):\n",
    "            for j in range(i, len(stones)):\n",
    "                if i == j:\n",
    "                    dp[i][j] = max(dp[i][j],0)\n",
    "                else:\n",
    "                    dp[i][j] = max(pre_sum[j + 1] - pre_sum[i + 1] - dp[i + 1][j], pre_sum[j ] - pre_sum[i] - dp[i][j - 1])\n",
    "        \n",
    "        return dp[0][len(stones) - 1]\n",
    "\n",
    "\n",
    "\n",
    "        @cache\n",
    "        def dfs(left, right, status):\n",
    "            if left >= right:\n",
    "                return 0\n",
    "\n",
    "            if status == 0:\n",
    "                left_ans = pre_sum[right + 1] - pre_sum[left + 1] + dfs(left + 1, right, 1)\n",
    "                right_ans = pre_sum[right ] - pre_sum[left ] + dfs(left, right - 1, 1)\n",
    "                return max(left_ans, right_ans)\n",
    "            else:\n",
    "                left_ans = -(pre_sum[right + 1] - pre_sum[left + 1]) + dfs(left + 1, right, 0)\n",
    "                right_ans = -(pre_sum[right ] - pre_sum[left ]) + dfs(left, right - 1, 0)\n",
    "                return min(left_ans, right_ans)\n",
    "        \n",
    "        return dfs(0, len(stones) - 1, 0)\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        length = len(stones)\n",
    "        sum_matrix = [[0 for _ in range(length)] for _ in range(length)]\n",
    "        for i in range(length):\n",
    "            sum_matrix[i][i] = stones[i]\n",
    "            for j in range(i+1, length):\n",
    "                sum_matrix[i][j] = stones[j] + sum_matrix[i][j-1]\n",
    "        dp = [[0 for _ in range(length)] for _ in range(length)]\n",
    "        for i in range(length-1, -1, -1):\n",
    "            for j in range(length):\n",
    "                if i == j:\n",
    "                    dp[i][j] = 0\n",
    "                elif j - i == 1:\n",
    "                    dp[i][j] = max(stones[i:j+1])\n",
    "                elif j - i > 1:\n",
    "                    dp[i][j] = max(sum_matrix[i+1][j] - dp[i+1][j], \n",
    "                                sum_matrix[i][j-1] - dp[i][j-1])\n",
    "        return dp[0][length-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "\n",
    "        flag = (n - 1) % 2\n",
    "        seen = dict()\n",
    "        # @cache\n",
    "        def dfs(i: int, j: int) -> int:\n",
    "            if i >= j: return 0\n",
    "            if (i+2,j) not in seen:\n",
    "                seen[i+2,j] = dfs(i+2,j)\n",
    "            if (i+1,j-1) not in seen:\n",
    "                seen[i+1,j-1] = dfs(i+1,j-1)\n",
    "            if (i,j-2) not in seen:\n",
    "                seen[i,j-2] = dfs(i,j-2)\n",
    "            if (i + j) % 2 == flag:\n",
    "                return max(\n",
    "                    min(seen[i + 2, j] + stones[i + 1], seen[i + 1, j - 1] + stones[j]),\n",
    "                    min(seen[i, j - 2] + stones[j - 1], seen[i + 1, j - 1] + stones[i])\n",
    "                )\n",
    "            else:\n",
    "                return min(\n",
    "                    max(seen[i + 2, j] - stones[i + 1], seen[i + 1, j - 1] - stones[j]),\n",
    "                    max(seen[i, j - 2] - stones[j - 1], seen[i + 1, j - 1] - stones[i])\n",
    "                )\n",
    "        ans = dfs(0, n - 1)\n",
    "        del seen\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "\n",
    "        # flag = (n - 1) % 2\n",
    "\n",
    "        @cache\n",
    "        def dfs(i: int, j: int) -> int:\n",
    "            if i >= j: return 0\n",
    "            # if (i + j) % 2 == flag:\n",
    "            return max(\n",
    "                min(dfs(i + 2, j) + stones[i + 1], dfs(i + 1, j - 1) + stones[j]),\n",
    "                min(dfs(i, j - 2) + stones[j - 1], dfs(i + 1, j - 1) + stones[i])\n",
    "            )\n",
    "            # else:\n",
    "            #     return min(\n",
    "            #         max(dfs(i + 2, j) - stones[i + 1], dfs(i + 1, j - 1) - stones[j]),\n",
    "            #         max(dfs(i, j - 2) - stones[j - 1], dfs(i + 1, j - 1) - stones[i])\n",
    "            #     )\n",
    "        ans = dfs(0, n - 1)\n",
    "        # print(dfs.cache_info())\n",
    "        dfs.cache_clear()\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "\n",
    "        flag = (n - 1) % 2\n",
    "\n",
    "        @cache\n",
    "        def dfs(i: int, j: int) -> int:\n",
    "            if i >= j: return 0\n",
    "            # if (i + j) % 2 == flag:\n",
    "            return max(\n",
    "                min(dfs(i + 2, j) + stones[i + 1], dfs(i + 1, j - 1) + stones[j]),\n",
    "                min(dfs(i, j - 2) + stones[j - 1], dfs(i + 1, j - 1) + stones[i])\n",
    "            )\n",
    "            # else:\n",
    "            #     return min(\n",
    "            #         max(dfs(i + 2, j) - stones[i + 1], dfs(i + 1, j - 1) - stones[j]),\n",
    "            #         max(dfs(i, j - 2) - stones[j - 1], dfs(i + 1, j - 1) - stones[i])\n",
    "            #     )\n",
    "        ans = dfs(0, n - 1)\n",
    "        # print(dfs.cache_info())\n",
    "        dfs.cache_clear()\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "\n",
    "        flag = (n - 1) % 2\n",
    "\n",
    "        @cache\n",
    "        def dfs(i: int, j: int) -> int:\n",
    "            if i >= j: return 0\n",
    "            if (i + j) % 2 == flag:\n",
    "                return max(\n",
    "                    min(dfs(i + 2, j) + stones[i + 1], dfs(i + 1, j - 1) + stones[j]),\n",
    "                    min(dfs(i, j - 2) + stones[j - 1], dfs(i + 1, j - 1) + stones[i])\n",
    "                )\n",
    "            else:\n",
    "                return min(\n",
    "                    max(dfs(i + 2, j) - stones[i + 1], dfs(i + 1, j - 1) - stones[j]),\n",
    "                    max(dfs(i, j - 2) - stones[j - 1], dfs(i + 1, j - 1) - stones[i])\n",
    "                )\n",
    "        ans = dfs(0, n - 1)\n",
    "        dfs.cache_clear()\n",
    "        return ans\n",
    "        # return dfs(0, n - 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from itertools import accumulate\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        add_sum = list(accumulate(stones, initial=0))\n",
    "        dp = [[[0]*2 for _ in range(n)] for _ in range(n)]\n",
    "        for i in range(n):\n",
    "            dp[i][i][0], dp[i][i][1] = 0, 0\n",
    "        for L in range(2, n+1):\n",
    "            for i in range(0, n-L+1):\n",
    "                l,r = i,i+L-1\n",
    "                ld = dp[l+1][r][1] + add_sum[r+1]-add_sum[l+1] - dp[l+1][r][0]\n",
    "                rd = dp[l][r-1][1] + add_sum[r]-add_sum[l] - dp[l][r-1][0]\n",
    "                if ld>rd:\n",
    "                    dp[l][r][0],dp[l][r][1] = dp[l+1][r][1] + add_sum[r+1]-add_sum[l+1],dp[l+1][r][0]\n",
    "                else:\n",
    "                    dp[l][r][0],dp[l][r][1] = dp[l][r-1][1] + add_sum[r]-add_sum[l], dp[l][r-1][0]\n",
    "                    \n",
    "        return dp[0][n-1][0] - dp[0][n-1][1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from itertools import accumulate\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        # 区间DP，判断的条件与石子游戏877不同的是，877是让先手者石子更多\n",
    "        # 这题是让先手者与后手者的差距更大\n",
    "        n = len(stones)\n",
    "        add_sum = list(accumulate(stones, initial=0))\n",
    "        dp = [[[0]*2 for _ in range(n)] for _ in range(n)]\n",
    "        for i in range(n):\n",
    "            dp[i][i][0], dp[i][i][1] = 0, 0\n",
    "        for L in range(2, n+1):\n",
    "            for i in range(0, n-L+1):\n",
    "                l,r = i,i+L-1\n",
    "                ld = dp[l+1][r][1] + add_sum[r+1]-add_sum[l+1] - dp[l+1][r][0]\n",
    "                rd = dp[l][r-1][1] + add_sum[r]-add_sum[l] - dp[l][r-1][0]\n",
    "                if ld>rd:\n",
    "                    dp[l][r][0],dp[l][r][1] = dp[l+1][r][1] + add_sum[r+1]-add_sum[l+1],dp[l+1][r][0]\n",
    "                else:\n",
    "                    dp[l][r][0],dp[l][r][1] = dp[l][r-1][1] + add_sum[r]-add_sum[l], dp[l][r-1][0]\n",
    "                    \n",
    "        return dp[0][n-1][0] - dp[0][n-1][1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        s = list(accumulate(stones, initial=0))\n",
    "        @cache\n",
    "        def dfs(i, j):\n",
    "            if i == j:\n",
    "                return 0\n",
    "            return max(s[j + 1] - s[i + 1] - dfs(i + 1, j), s[j] - s[i] - dfs(i, j - 1))\n",
    "        res = dfs(0, len(stones) - 1)\n",
    "        del dfs\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "# class Solution:\n",
    "#     def stoneGameVII(self, stones: List[int]) -> int:\n",
    "#         pre = list(accumulate(stones))\n",
    "#         ans = 0\n",
    "#         @lru_cache(None)\n",
    "#         def dfs(l,r,flag):   \n",
    "#             nonlocal ans         \n",
    "#             if l >= r:\n",
    "#                 return 0\n",
    "#             lnum,rnum = pre[r-1]-(pre[l-1] if l!=0 else 0), pre[r]-pre[l]\n",
    "#             if flag:\n",
    "#                 if lnum > rnum:\n",
    "#                     ans += lnum\n",
    "#                     dfs(l,r-1)\n",
    "#                 elif lnum < rnum:\n",
    "#                     ans += rnum\n",
    "#                     dfs(l+1,r)\n",
    "#                 else:\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        pre = list(accumulate(stones,initial=0))\n",
    "        @cache\n",
    "        def dfs(i, j):\n",
    "            if i >= j: return 0\n",
    "            return max(pre[j + 1] - pre[i + 1] - dfs(i + 1, j), pre[j] - pre[i] - dfs(i, j - 1))\n",
    "        res = dfs(0, len(stones) - 1)\n",
    "        dfs.cache_clear()\n",
    "        return res        \n",
    "            \n",
    "        \n",
    "        \n",
    "            \n",
    "            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        s = list(accumulate(stones, initial=0))\n",
    "        @cache\n",
    "        def dfs(i, j):\n",
    "            if i == j:\n",
    "                return 0\n",
    "            return max(s[j + 1] - s[i + 1] - dfs(i + 1, j), s[j] - s[i] - dfs(i, j - 1))\n",
    "        res = dfs(0, len(stones) - 1)\n",
    "        dfs.cache_clear()\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        s = [0] * n\n",
    "        for i, x in enumerate(stones):\n",
    "            s[i] = x + (s[i - 1] if i > 0 else 0)\n",
    "        # print(f's:{s}')\n",
    "        def val(i: int, j: int) -> int:\n",
    "            return s[j] - (s[i - 1] if i > 0 else 0)\n",
    "        @cache\n",
    "        def dfs(i: int, j: int, a: bool) -> int:\n",
    "            if i == j:\n",
    "                # print(f'i:{i},j:{j},a:{a}')\n",
    "                return 0\n",
    "            if a:\n",
    "                ans = max(dfs(i + 1, j, False) + val(i + 1, j), dfs(i, j - 1, False) + val(i, j - 1))\n",
    "                # print(f'ans:{ans},i:{i},j:{j},a:{a}')\n",
    "                return ans\n",
    "            else:\n",
    "                ans = min(dfs(i + 1, j, True) - val(i + 1, j), dfs(i, j - 1, True) - val(i, j - 1))\n",
    "                # print(f'ans:{ans},i:{i},j:{j},a:{a}')\n",
    "                return ans\n",
    "        ans = dfs(0, n - 1, True)\n",
    "        dfs.cache_clear()\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        pre_sum = list(accumulate(stones, initial=0))\n",
    "        # 区间DP\n",
    "        @cache\n",
    "        def dfs(l, r):\n",
    "            if l >= r: # 只有一个元素，移除之后，没有剩余的石子，没有得分，差值也是0\n",
    "                return 0\n",
    "            # 移除l,得分为[l+1..r]的和\n",
    "            # 移除r,得分为[l..r-1]的和\n",
    "            res1 = pre_sum[r+1] - pre_sum[l+1] - dfs(l+1, r) # 两位玩家的得分差值\n",
    "            res2 = pre_sum[r] - pre_sum[l] - dfs(l, r-1) \n",
    "            return max(res1, res2)\n",
    "        res = dfs(0, len(stones) - 1)\n",
    "        dfs.cache_clear()\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "\n",
    "        n = len(stones)\n",
    "        pre = list(accumulate(stones, initial=0))\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def dfs(i, j):\n",
    "            if i == j:\n",
    "                return 0\n",
    "            return max(-dfs(i+1, j) + pre[j+1]-pre[i+1], -dfs(i, j-1)+pre[j]-pre[i])\n",
    "        ans =  dfs(0, n-1)\n",
    "        dfs.cache_clear()\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "\n",
    "        s = list(accumulate(stones, initial=0))\n",
    "        @cache \n",
    "        def dfs(i: int, j: int) -> int:\n",
    "            if i == j:\n",
    "                return 0\n",
    "            return max(s[j + 1] - s[i + 1] - dfs(i + 1, j), s[j] - s[i] - dfs(i, j - 1))\n",
    "\n",
    "        res = dfs(0, len(stones) - 1)\n",
    "        dfs.cache_clear()\n",
    "        return res \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        s = [0] * n\n",
    "        for i, x in enumerate(stones):\n",
    "            s[i] = x + (s[i - 1] if i > 0 else 0)\n",
    "        # print(f's:{s}')\n",
    "        def val(i: int, j: int) -> int:\n",
    "            return s[j] - (s[i - 1] if i > 0 else 0)\n",
    "        @cache\n",
    "        def dfs(i: int, j: int) -> int:\n",
    "            if i == j:\n",
    "                # print(f'i:{i},j:{j},a:{a}')\n",
    "                return 0\n",
    "            return max(val(i + 1, j) - dfs(i + 1, j), val(i, j - 1) - dfs(i, j - 1))\n",
    "        ans = dfs(0, n - 1)\n",
    "        dfs.cache_clear()\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "# class Solution:\n",
    "#     def stoneGameVII(self, stones: List[int]) -> int:\n",
    "#         pre = list(accumulate(stones))\n",
    "#         ans = 0\n",
    "#         @lru_cache(None)\n",
    "#         def dfs(l,r,flag):   \n",
    "#             nonlocal ans         \n",
    "#             if l >= r:\n",
    "#                 return 0\n",
    "#             lnum,rnum = pre[r-1]-(pre[l-1] if l!=0 else 0), pre[r]-pre[l]\n",
    "#             if flag:\n",
    "#                 if lnum > rnum:\n",
    "#                     ans += lnum\n",
    "#                     dfs(l,r-1)\n",
    "#                 elif lnum < rnum:\n",
    "#                     ans += rnum\n",
    "#                     dfs(l+1,r)\n",
    "#                 else:\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        # pre = [0]\n",
    "        # for s in stones:\n",
    "        #     pre.append(pre[-1] + s)\n",
    "        pre = list(accumulate(stones,initial=0))\n",
    "        @cache\n",
    "        def dfs(i, j):\n",
    "            if i > j: return 0\n",
    "            return max(pre[j + 1] - pre[i + 1] - dfs(i + 1, j), pre[j] - pre[i] - dfs(i, j - 1))\n",
    "        res = dfs(0, len(stones) - 1)\n",
    "        dfs.cache_clear()\n",
    "        return res        \n",
    "            \n",
    "        \n",
    "        \n",
    "            \n",
    "            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "# class Solution:\n",
    "#     def stoneGameVII(self, stones: List[int]) -> int:\n",
    "#         pre = list(accumulate(stones))\n",
    "#         ans = 0\n",
    "#         @lru_cache(None)\n",
    "#         def dfs(l,r,flag):   \n",
    "#             nonlocal ans         \n",
    "#             if l >= r:\n",
    "#                 return 0\n",
    "#             lnum,rnum = pre[r-1]-(pre[l-1] if l!=0 else 0), pre[r]-pre[l]\n",
    "#             if flag:\n",
    "#                 if lnum > rnum:\n",
    "#                     ans += lnum\n",
    "#                     dfs(l,r-1)\n",
    "#                 elif lnum < rnum:\n",
    "#                     ans += rnum\n",
    "#                     dfs(l+1,r)\n",
    "#                 else:\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        pre = [0]\n",
    "        for s in stones:\n",
    "            pre.append(pre[-1] + s)\n",
    "        \n",
    "        @cache\n",
    "        def dfs(i, j):\n",
    "            if i > j: return 0\n",
    "            return max(pre[j + 1] - pre[i + 1] - dfs(i + 1, j), pre[j] - pre[i] - dfs(i, j - 1))\n",
    "        res = dfs(0, len(stones) - 1)\n",
    "        dfs.cache_clear()\n",
    "        return res        \n",
    "            \n",
    "        \n",
    "        \n",
    "            \n",
    "            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        pre_sum = [0]\n",
    "        for x in stones:\n",
    "            pre_sum.append(x + pre_sum[-1])\n",
    "        print(pre_sum)\n",
    "        @cache\n",
    "        def dfs(l:int, r:int):\n",
    "            if l == r:\n",
    "                return 0\n",
    "            return max(pre_sum[r+1] - pre_sum[l+1] - dfs(l+1, r), pre_sum[r] - pre_sum[l] - dfs(l, r-1))\n",
    "        res = dfs(0, n-1)\n",
    "        dfs.cache_clear()\n",
    "        return res\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "# class Solution:\n",
    "#     def stoneGameVII(self, stones: List[int]) -> int:\n",
    "#         pre = list(accumulate(stones))\n",
    "#         ans = 0\n",
    "#         @lru_cache(None)\n",
    "#         def dfs(l,r,flag):   \n",
    "#             nonlocal ans         \n",
    "#             if l >= r:\n",
    "#                 return 0\n",
    "#             lnum,rnum = pre[r-1]-(pre[l-1] if l!=0 else 0), pre[r]-pre[l]\n",
    "#             if flag:\n",
    "#                 if lnum > rnum:\n",
    "#                     ans += lnum\n",
    "#                     dfs(l,r-1)\n",
    "#                 elif lnum < rnum:\n",
    "#                     ans += rnum\n",
    "#                     dfs(l+1,r)\n",
    "#                 else:\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        pre = [0]\n",
    "        for s in stones:\n",
    "            pre.append(pre[-1] + s)\n",
    "        \n",
    "        @cache\n",
    "        def dfs(i, j):\n",
    "            if i > j: return 0\n",
    "            return max(pre[j + 1] - pre[i + 1] - dfs(i + 1, j), pre[j] - pre[i] - dfs(i, j - 1))\n",
    "        res = dfs(0, len(stones) - 1)\n",
    "        dfs.cache_clear()\n",
    "        return res        \n",
    "            \n",
    "        \n",
    "        \n",
    "            \n",
    "            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        # 先手对后手的净胜分\n",
    "        @cache\n",
    "        def dfs(i,j):\n",
    "            if i>j:return 0\n",
    "            return max(presum[j+1]-presum[i]-stones[i]-dfs(i+1,j),presum[j+1]-presum[i]-stones[j]-dfs(i,j-1))\n",
    "        presum=list(itertools.accumulate(stones,initial=0))\n",
    "        n=len(stones)\n",
    "        res=dfs(0,n-1)\n",
    "        dfs.cache_clear()\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "\n",
    "# by hangpengjie\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        pre = [0]\n",
    "        for stone in stones:\n",
    "            pre.append(pre[-1] + stone)\n",
    "        dp = [[inf] * (n+1) for _ in range(n+1)]\n",
    "\n",
    "        def dfs(l:int,r:int)->int:\n",
    "            if l == r:\n",
    "                dp[l][r] = 0\n",
    "                return 0\n",
    "            if dp[l][r] != inf:\n",
    "                return dp[l][r]\n",
    "            r1 = -dfs(l+1,r) + pre[r] - pre[l]\n",
    "            r2 = -dfs(l,r-1) + pre[r-1] - pre[l-1]\n",
    "            dp[l][r] = max(r1,r2)\n",
    "            return dp[l][r]\n",
    "        return dfs(1,n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\r\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\r\n",
    "        n = len(stones)\r\n",
    "        s = list(accumulate(stones, initial=0))\r\n",
    "        memo = [[-1] * (n + 1) for _ in range(n + 1)]\r\n",
    "        def dfs(i: int, j: int) -> int:\r\n",
    "            if i == j:\r\n",
    "                return 0\r\n",
    "            if memo[i][j] != -1:\r\n",
    "                return memo[i][j]\r\n",
    "            memo[i][j] = max(s[j + 1] - s[i + 1] - dfs(i + 1, j), s[j] - s[i] - dfs(i, j - 1))\r\n",
    "            return memo[i][j]\r\n",
    "        return dfs(0, len(stones) - 1)\r\n",
    "\r\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        @lru_cache(maxsize = 1200000)\n",
    "        def dfs(l, r, score):\n",
    "            if l == r: return 0\n",
    "            return max(score - stones[l] - dfs(l + 1, r, score - stones[l]), score - stones[r] - dfs(l, r - 1, score - stones[r]))\n",
    "        ret = dfs(0, len(stones) - 1, sum(stones))\n",
    "        dfs.cache_clear()\n",
    "        return ret"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        s = [[0] * n for _ in range(n)]\n",
    "        for i in range(n):\n",
    "            s[i][i] = stones[i]\n",
    "            for j in range(i + 1, n):\n",
    "                s[i][j] = s[i][j - 1] + stones[j]\n",
    "        @cache\n",
    "        def dp(left, right):\n",
    "            if left == right:\n",
    "                return 0\n",
    "            return max(s[left + 1][right] - dp(left + 1, right), s[left][right - 1] - dp(left, right - 1))\n",
    "        return dp(0, n - 1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        total=sum(stones)\n",
    "        dp=total\n",
    "        for i in range(len(stones)-1,1,-1):\n",
    "            total-=stones[i]\n",
    "            dp=max(dp,total-dp)\n",
    "        return dp\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        s = list(accumulate(stones))\n",
    "        n = len(stones)\n",
    "        dp = s[-1]  #  从后向前，dp表示当前遍历到的所有stones后缀的，先手的最大差值 的最大值\n",
    "        # dp[-1] = 0\n",
    "        # dp[-2] = s[n-1]\n",
    "        # dp[-3] = max(s[n-1],s[n-2]-dp[-2]) = max(dp[-2],s[n-2]-dp[-2])\n",
    "        # dp[-4] = max(s[n-1],s[n-2]-dp[-2],s[n-3]-dp[-3]) = max(dp[-3],s[n-3]-dp[-3])\n",
    "        # ...\n",
    "        # dp[-2] = s[n-1], 从dp[-3] 开始推\n",
    "        for i in range(n - 3, -1, -1):\n",
    "            dp = max(dp, s[i + 1] - dp)\n",
    "        return dp"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        s = sum(stones)\n",
    "        res = s\n",
    "        for i in range(n-1, 1, -1):\n",
    "            s -= stones[i]\n",
    "            res = max(res, s - res)\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        for i in range(1, len(stones)):\n",
    "            stones[i] += stones[i - 1]\n",
    "        post_max = stones[-1]\n",
    "        for i in range(len(stones) - 2, 0, -1):\n",
    "            stones[i] -= post_max\n",
    "            post_max = max(post_max, stones[i])\n",
    "        return max(stones[1:])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        if len(stones) == 2:\n",
    "            return sum(stones)\n",
    "\n",
    "        best = [None for _ in stones]\n",
    "        best[-1] = S = sum(stones) # no other choice\n",
    "\n",
    "        best_diff = -inf\n",
    "        S_right = 0\n",
    "        for i in range(len(stones)-2, 0, -1):\n",
    "            S_right += stones[i+1]\n",
    "            if best_diff < S - S_right - best[i+1]:\n",
    "                best_diff = S - S_right - best[i+1]\n",
    "            best[i] = max(S, best_diff)\n",
    "        return best[1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        total=sum(stones)\n",
    "        dp=total\n",
    "        for i in range(len(stones)-1,1,-1):\n",
    "            total-=stones[i]\n",
    "            dp=max(dp,total-dp)\n",
    "        return dp\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        pre = [stones[0]] * n\n",
    "        for i in range(1, n):\n",
    "            pre[i] = pre[i - 1] + stones[i]\n",
    "        ans = pre[-1]\n",
    "        for i in range(n - 2, 0, -1):\n",
    "            ans = max(ans, pre[i] - ans)\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from typing import List\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        # Calculate prefix sum\n",
    "        for i in range(1, len(stones)):\n",
    "            stones[i] += stones[i - 1]\n",
    "\n",
    "        # Initialize dp array with last stone value\n",
    "        dp = stones[-1]\n",
    "\n",
    "        # Start decision from second last stone\n",
    "        for i in range(len(stones) - 2, 0, -1):\n",
    "            dp = max(dp, stones[i] - dp)\n",
    "        return dp\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "# class Solution:\n",
    "#     def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "#         # 移除并放回，前缀和不变\n",
    "#         # 每次拿的石子必然包括前面的前缀和\n",
    "#         @lru_cache(None)\n",
    "#         def dfs(idx):\n",
    "#             if idx >= n - 1:\n",
    "#                 return presum[n]\n",
    "#             # 不选当前坐标，选后面的会是dfs(idx+1),选当前坐标会得到presum[idx+1] - dfs(idx+1)。取两者最大值\n",
    "#             return max(dfs(idx + 1), presum[idx + 1] - dfs(idx+1))\n",
    "\n",
    "#         n = len(stones)\n",
    "#         presum = list(accumulate(stones,initial=0))\n",
    "#         return dfs(1)\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        f = [0] * n\n",
    "        pre = list(accumulate(stones))\n",
    "        f[-1] = pre[-1]\n",
    "        for i in range(n-2,0,-1):\n",
    "            f[i] = max(f[i+1],pre[i]-f[i+1])\n",
    "        return f[1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "# class Solution:\n",
    "#     def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "#         # 移除并放回，前缀和不变\n",
    "#         # 每次拿的石子必然包括前面的前缀和\n",
    "#         @lru_cache(None)\n",
    "#         def dfs(idx):\n",
    "#             if idx >= n - 1:\n",
    "#                 return presum[n]\n",
    "#             # 不选当前坐标，选后面的会是dfs(idx+1),选当前坐标会得到presum[idx+1] - dfs(idx+1)。取两者最大值\n",
    "#             return max(dfs(idx + 1), presum[idx + 1] - dfs(idx+1))\n",
    "\n",
    "#         n = len(stones)\n",
    "#         presum = list(accumulate(stones,initial=0))\n",
    "#         return dfs(1)\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        f = [0] * n\n",
    "        pre = list(accumulate(stones))\n",
    "        f[-1] = pre[-1]\n",
    "        for i in range(n-2,0,-1):\n",
    "            f[i] = max(f[i+1],pre[i]-f[i+1])\n",
    "        return f[1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "# class Solution:\n",
    "#     def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "#         # 移除并放回，前缀和不变\n",
    "#         # 每次拿的石子必然包括前面的前缀和\n",
    "#         @lru_cache(None)\n",
    "#         def dfs(idx):\n",
    "#             if idx >= n - 1:\n",
    "#                 return presum[n]\n",
    "#             # 不选当前坐标，选后面的会是dfs(idx+1),选当前坐标会得到presum[idx+1] - dfs(idx+1)。取两者最大值\n",
    "#             return max(dfs(idx + 1), presum[idx + 1] - dfs(idx+1))\n",
    "\n",
    "#         n = len(stones)\n",
    "#         presum = list(accumulate(stones,initial=0))\n",
    "#         return dfs(1)\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        pre = list(accumulate(stones))\n",
    "        f = [0] * n\n",
    "        f[n - 1] = pre[n - 1]\n",
    "        for i in range(n - 2, 0, -1):\n",
    "            f[i] = max(f[i + 1], pre[i] - f[i + 1])\n",
    "        return f[1]\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        pre = [stones[0]] * n\n",
    "        for i in range(1, n):\n",
    "            pre[i] = pre[i - 1] + stones[i]\n",
    "        score = [pre[-1]] * n\n",
    "        for i in range(n - 2, 0, -1):\n",
    "            score[i] = max(score[i + 1], pre[i] - score[i + 1])\n",
    "        return score[1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from itertools import accumulate\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        #dp[i]表示先手者在区间[i,n)内选择能达到的最大分差\n",
    "        pre = list(accumulate(stones))\n",
    "        n = len(stones)\n",
    "        dp = [0]*n\n",
    "        dp[n-1] = pre[n-1]\n",
    "        for i in range(n-2, 0, -1):\n",
    "            dp[i] = max(dp[i+1], pre[i]-dp[i+1])\n",
    "        return dp[1]\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        \n",
    "        n=len(stones)\n",
    "        pre=[0]*n\n",
    "        pre[0]=stones[0]\n",
    "        for i in range(1,n):\n",
    "            pre[i]=pre[i-1]+stones[i]\n",
    "        \n",
    "        dp=[0]*n\n",
    "        dp[-1]=pre[-1]\n",
    "        ans=dp[-1]\n",
    "        for i in range(n-2,0,-1):\n",
    "            dp[i]=max(dp[i+1],pre[i]-dp[i+1])\n",
    "            ans=max(ans,dp[i])\n",
    "        \n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        s = list(accumulate(stones))\n",
    "        f = s[-1]\n",
    "        for i in range(len(s) - 2, 0, -1):\n",
    "            f = max(f, s[i] - f)\n",
    "        return f"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "# class Solution:\n",
    "#     def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "#         # 移除并放回，前缀和不变\n",
    "#         # 每次拿的石子必然包括前面的前缀和\n",
    "#         @lru_cache(None)\n",
    "#         def dfs(idx):\n",
    "#             if idx >= n - 1:\n",
    "#                 return presum[n]\n",
    "#             # 不选当前坐标，选后面的会是dfs(idx+1),选当前坐标会得到presum[idx+1] - dfs(idx+1)。取两者最大值\n",
    "#             return max(dfs(idx + 1), presum[idx + 1] - dfs(idx+1))\n",
    "\n",
    "#         n = len(stones)\n",
    "#         presum = list(accumulate(stones,initial=0))\n",
    "#         return dfs(1)\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        f = [0] * n\n",
    "        pre = list(accumulate(stones))\n",
    "        f[-1] = pre[-1]\n",
    "        for i in range(n-2,0,-1):\n",
    "            f[i] = max(f[i+1],pre[i]-f[i+1])\n",
    "        return f[1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        for i in range(1, n):\n",
    "            stones[i] += stones[i - 1]\n",
    "        dp = [int(-2e9) for _ in range(n)]\n",
    "        dpmi = [0 for _ in range(n)]\n",
    "        dp[n - 1] = stones[n - 1]\n",
    "        mi = -stones[n - 1]\n",
    "        if n - 2 > 0:\n",
    "            dp[n - 2] = mi + stones[n - 2]\n",
    "            dp[n - 2] = max(dp[n - 2], dp[n - 1]) \n",
    "        for i in reversed(range(1, n - 2)):\n",
    "            mi = min(mi, dp[i + 2] - stones[i + 1])\n",
    "            dp[i] = mi + stones[i]\n",
    "            dp[i] = max(dp[i], dp[i + 1])\n",
    "        return dp[1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        ps = [0] + list(accumulate(stones))\n",
    "        # @cache\n",
    "        # def dfs(u):\n",
    "        #     if u == n - 1: return ps[n]\n",
    "        #     return max(dfs(u + 1), ps[u + 1] - dfs(u + 1))\n",
    "        # return dfs(1)\n",
    "        f = [0] * (n + 1)\n",
    "        f[-1] = ps[-1]\n",
    "        for i in range(n - 1, 1, -1):\n",
    "            f[i] = max(f[i + 1], ps[i] - f[i + 1])\n",
    "        return f[2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        for i in range(1, n):\n",
    "            stones[i] += stones[i - 1]\n",
    "        dp = [int(-2e9) for _ in range(n)]\n",
    "        dpmi = [0 for _ in range(n)]\n",
    "        dp[n - 1] = stones[n - 1]\n",
    "        mi = -stones[n - 1]\n",
    "        if n - 2 > 0:\n",
    "            dp[n - 2] = mi + stones[n - 2]\n",
    "            dp[n - 2] = max(dp[n - 2], dp[n - 1]) \n",
    "        for i in reversed(range(1, n - 2)):\n",
    "            mi = min(mi, dp[i + 2] - stones[i + 1])\n",
    "            dp[i] = mi + stones[i]\n",
    "            dp[i] = max(dp[i], dp[i + 1])\n",
    "        return dp[1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        for i in range(1, n):\n",
    "            stones[i] += stones[i - 1]\n",
    "        dp = [int(-2e9) for _ in range(n)]\n",
    "        dpmi = [0 for _ in range(n)]\n",
    "        dp[n - 1] = stones[n - 1]\n",
    "        mi = -stones[n - 1]\n",
    "        dp[n - 2] = mi + stones[n - 2]\n",
    "        dp[n - 2] = max(dp[n - 2], dp[n - 1]) \n",
    "        for i in reversed(range(1, n - 2)):\n",
    "            mi = min(mi, dp[i + 2] - stones[i + 1])\n",
    "            dp[i] = mi + stones[i]\n",
    "            dp[i] = max(dp[i], dp[i + 1])\n",
    "        return dp[1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        acc = list(accumulate(stones))\n",
    "        n = len(stones)\n",
    "        f = [0] * n \n",
    "        f[-1] = acc[-1]\n",
    "        for i in range(n - 2, -1, -1):\n",
    "            f[i] = max(acc[i] - f[i + 1], f[i + 1])\n",
    "        return f[1]\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        for i in range(1, n):\n",
    "            stones[i] += stones[i - 1]\n",
    "        dp = [int(-2e9) for _ in range(n)]\n",
    "        dpmi = [0 for _ in range(n)]\n",
    "        dp[n - 1] = stones[n - 1]\n",
    "        mi = -stones[n - 1]\n",
    "        if n - 2 > 0:\n",
    "            dp[n - 2] = mi + stones[n - 2]\n",
    "            dp[n - 2] = max(dp[n - 2], dp[n - 1]) \n",
    "        for i in reversed(range(1, n - 2)):\n",
    "            mi = min(mi, dp[i + 2] - stones[i + 1])\n",
    "            dp[i] = mi + stones[i]\n",
    "            dp[i] = max(dp[i], dp[i + 1])\n",
    "        return dp[1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        for i in range(1, n):\n",
    "            stones[i] += stones[i - 1]\n",
    "        dp = [int(-2e9) for _ in range(n)]\n",
    "        dpmi = [0 for _ in range(n)]\n",
    "        dp[n - 1] = stones[n - 1]\n",
    "        mi = -stones[n - 1]\n",
    "        dp[n - 2] = mi + stones[n - 2]\n",
    "        dp[n - 2] = max(dp[n - 2], dp[n - 1]) \n",
    "        for i in reversed(range(1, n - 2)):\n",
    "            mi = min(mi, dp[i + 2] - stones[i + 1])\n",
    "            dp[i] = mi + stones[i]\n",
    "            dp[i] = max(dp[i], dp[i + 1])\n",
    "        return dp[1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        S = stones[::]\n",
    "        for i in range(1, n):\n",
    "            S[i] += S[i-1]\n",
    "\n",
    "        dp1 = [-0x7fffffff] * n\n",
    "        dp2 = [0x7fffffff] * n\n",
    "        dp1[n-1] = S[n-1]\n",
    "        dp2[n-1] = -S[n-1]\n",
    "\n",
    "        min_dp1 = -S[n-1]\n",
    "        max_dp2 = S[n-1]\n",
    "        for i in range(n-2, -1, -1):\n",
    "            if i == 0:\n",
    "                dp1[i] = max_dp2\n",
    "            else:\n",
    "                max_dp2 = max(max_dp2, S[i] + dp2[i+1])\n",
    "                dp1[i] = max_dp2\n",
    "\n",
    "            if i == 0:\n",
    "                dp2[i] = min_dp1\n",
    "            else:\n",
    "                min_dp1 = min(min_dp1, dp1[i+1] - S[i])\n",
    "                dp2[i] = min_dp1\n",
    "\n",
    "        return dp1[0]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        pre = list(itertools.accumulate(stones)) \n",
    "        n = len(stones)\n",
    "        dp = [-sys.maxsize] * n     \n",
    "        for ith in range(n-1, 0, -1):\n",
    "            dp[ith] = max(dp[ith + 1], pre[ith] - dp[ith+1]) if ith < n-1 else pre[ith]\n",
    "\n",
    "        return dp[1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        pre = list(itertools.accumulate(stones)) \n",
    "        n = len(stones)\n",
    "        dp = [-sys.maxsize] * n     \n",
    "        for ith in range(n-1, 0, -1):\n",
    "            dp[ith] = max(dp[ith + 1], pre[ith] - dp[ith+1]) if ith < n-1 else pre[ith]\n",
    "\n",
    "        return dp[1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        S = stones[::]\n",
    "        for i in range(1, n):\n",
    "            S[i] += S[i-1]\n",
    "\n",
    "        dp1 = [-0x7fffffff] * n\n",
    "        dp2 = [0x7fffffff] * n\n",
    "        dp1[n-1] = S[n-1]\n",
    "        dp2[n-1] = -S[n-1]\n",
    "\n",
    "        min_dp1 = -S[n-1]\n",
    "        max_dp2 = S[n-1]\n",
    "        for i in range(n-2, -1, -1):\n",
    "            if i == 0:\n",
    "                dp1[i] = max_dp2\n",
    "            else:\n",
    "                max_dp2 = max(max_dp2, S[i] + dp2[i+1])\n",
    "                dp1[i] = max_dp2\n",
    "\n",
    "            if i == 0:\n",
    "                dp2[i] = min_dp1\n",
    "            else:\n",
    "                min_dp1 = min(min_dp1, dp1[i+1] - S[i])\n",
    "                dp2[i] = min_dp1\n",
    "\n",
    "        return dp1[0]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        a,b=0,0\n",
    "        n=len(stones)\n",
    "        pre=[0]*(n+1)\n",
    "        for i in range(n):\n",
    "            pre[i+1]=pre[i]+stones[i]\n",
    "        pre=pre[1:]\n",
    "        dp=[0]*n\n",
    "        dp[-1]=pre[-1]\n",
    "        for i in range(n-2,0,-1):\n",
    "            dp[i]=max(dp[i+1],pre[i]-dp[i+1])\n",
    "        print(dp)\n",
    "        return dp[1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        l = len(stones)\n",
    "        s = [stones[0]] * l\n",
    "        for i in range(1, l):\n",
    "            s[i] = stones[i] + s[i - 1]\n",
    "        dp = [0] * (l - 1) + [s[-1]]\n",
    "        right = s[-1]\n",
    "        for i in range(l - 2, -1, -1):\n",
    "            dp[i] = s[i] - right\n",
    "            right = max(right, dp[i])\n",
    "        return max(dp[1:])\n",
    "\n",
    "\n",
    "            \n",
    "        \n",
    "            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        N = len(stones)\n",
    "        pre = [stones[0]]*N\n",
    "        for i in range(1,N):\n",
    "            pre[i] = pre[i-1]+stones[i]\n",
    "        dp = [ [0]*2 for i in range(N+1)]\n",
    "        dp[N-1] = [pre[-1],pre[-1]]\n",
    "        ret = 0\n",
    "        for i in range(N-2,0,-1):\n",
    "            right,subdiff = dp[i+1]\n",
    "            left = right-subdiff+pre[i]\n",
    "            # print(left,right,subdiff)\n",
    "            if left-right>subdiff:\n",
    "                diff = left-right\n",
    "            else:\n",
    "                left = right \n",
    "                diff=subdiff\n",
    "            dp[i] = [left,diff]\n",
    "        # print(pre,dp)\n",
    "        return dp[1][1] \n",
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        ps = list(accumulate(stones, initial=0))\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def dfs(idx):\n",
    "            if idx == n - 1:\n",
    "                return ps[-1]\n",
    "            \n",
    "            return max(dfs(idx + 1), ps[idx + 1] - dfs(idx + 1))\n",
    "        \n",
    "        ans = dfs(1)\n",
    "        dfs.cache_clear()\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        # 移除并放回，前缀和不变\n",
    "        # 每次拿的石子必然包括前面的前缀和\n",
    "        @lru_cache(None)\n",
    "        def dfs(idx):\n",
    "            if idx >= n - 1:\n",
    "                return presum[n]\n",
    "            # 不选当前坐标，选后面的会是dfs(idx+1),选当前坐标会得到presum[idx+1] - dfs(idx+1)。取两者最大值\n",
    "            return max(dfs(idx + 1), presum[idx + 1] - dfs(idx+1))\n",
    "\n",
    "        n = len(stones)\n",
    "        presum = list(accumulate(stones,initial=0))\n",
    "        return dfs(1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        if n == 2:\n",
    "            return sum(stones)\n",
    "\n",
    "        p = list(accumulate(stones))\n",
    "\n",
    "        @cache\n",
    "        def dfs(i):\n",
    "            if i == n - 1:\n",
    "                return p[-1]\n",
    "            res = max(dfs(i + 1), p[i] - dfs(i + 1))\n",
    "            return res\n",
    "\n",
    "        return dfs(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        pre = list(accumulate(stones))\n",
    "        @cache\n",
    "        def f(i):\n",
    "            if i == n-1:\n",
    "                return pre[i]\n",
    "\n",
    "            return max(f(i+1), pre[i]-f(i+1))\n",
    "        return f(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGameVIII(self, stones: List[int]) -> int:\n",
    "        n = len(stones)\n",
    "        pre = list(accumulate(stones))\n",
    "        @cache\n",
    "        def f(i):\n",
    "            if i == n-1:\n",
    "                return pre[i]\n",
    "\n",
    "            return max(f(i+1), pre[i]-f(i+1))\n",
    "        return f(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        return True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles):\n",
    "        \"\"\"\n",
    "        :type piles: List[int]\n",
    "        :rtype: bool\n",
    "        \"\"\"\n",
    "        return True\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        return True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        return True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        return True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        return True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        n = len(piles)\n",
    "        f = [[[0, 0]] * n for _ in range(n)]\n",
    "        for i in range(n):\n",
    "            f[i][i][0] = piles[i]\n",
    "            f[i][i][1] = 0 \n",
    "        for i in range(n - 2, -1, -1):\n",
    "            for j in range(i + 1, n):\n",
    "                left = piles[i] + f[i+1][j][1]\n",
    "                right = piles[j] + f[i][j-1][1]\n",
    "                if left > right:\n",
    "                    f[i][j][0] = left\n",
    "                    f[i][j][1] = f[i+1][j][0]\n",
    "                else:\n",
    "                    f[i][j][0] = right\n",
    "                    f[i][j][1] = f[i][j-1][1]\n",
    "        return f[0][n-1][0] - f[0][n-1][1] > 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        dp = [[0]*len(piles) for _ in range(len(piles))]\n",
    "        for interval in range(2,len(piles)+2,2):\n",
    "            for start in range(0,len(piles)-interval+1):\n",
    "                if interval==2:\n",
    "                    dp[start][start+interval-1]=abs(piles[start]-piles[start+1])\n",
    "                else:\n",
    "                    rs1 = dp[start+2][start+interval-1]+piles[start]-piles[start+1]\n",
    "                    rs2 = dp[start][start+interval-2-1]+piles[start+interval-1]-piles[start+interval-1-1]\n",
    "                    rs3 = dp[start+1][start+interval-1-1]+abs(piles[start]-piles[start+interval-1])\n",
    "                    dp[start][start+interval-1]=max(max(rs1,rs2),rs3)\n",
    "        if dp[0][-1]>0:\n",
    "            return True\n",
    "        else:\n",
    "            return False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        n = len(piles)\n",
    "        dp = [ [0]*n for _ in range(n)]\n",
    "\n",
    "        for i,pile in enumerate(piles):\n",
    "            dp[i][i] = pile\n",
    "        #i<j\n",
    "        for i in range(n-2, -1,-1):\n",
    "            for j in range(i+1, n):\n",
    "                dp[i][j] = max(piles[i]-dp[i+1][j], piles[j]-dp[i][j-1])\n",
    "\n",
    "        return dp[0][n-1]>0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        dp = [[0 for j in range(len(piles))] for i in range(len(piles))]\n",
    "        for i in range(len(piles)-1, -1, -1):\n",
    "            for j in range(len(piles)):\n",
    "                if i > j:\n",
    "                    continue\n",
    "                elif i == j:\n",
    "                    dp[i][j] = piles[i]\n",
    "                elif j == i+1:\n",
    "                    dp[i][j] = max(piles[i], piles[j])\n",
    "                else:\n",
    "                    dp[i][j] = max(piles[i]+sum(piles[i+1:j+1])-dp[i+1][j],\n",
    "                    piles[j]+sum(piles[i:j])-dp[i][j-1])\n",
    "        \n",
    "        return dp[0][-1] > sum(piles)-dp[0][-1]\n",
    "                "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        # 动态规划\n",
    "        N = len(piles)\n",
    "        fmap = [[0 for j in range(N)]for i in range(N)]\n",
    "        gmap = [[0 for j in range(N)]for i in range(N)]\n",
    "        for i in range(N):\n",
    "            fmap[i][i] = piles[i]\n",
    "        for startcol in range(1,N):\n",
    "            L , R = 0 ,startcol\n",
    "            while R < N:\n",
    "                fmap[L][R] = max(piles[L] + gmap[L+1][R],piles[R] + gmap[L][R-1])\n",
    "                gmap[L][R] = min(fmap[L+1][R],fmap[L][R-1])\n",
    "                L += 1\n",
    "                R += 1\n",
    "        return fmap[0][N-1] > gmap[0][N-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        n=len(piles)\n",
    "        dp=[[0]*n for _ in range(n)]\n",
    "        for i in range(n):\n",
    "            dp[i][i]=piles[i]\n",
    "        for l in range(n-2,-1,-1):\n",
    "            for r in range(l+1,n):\n",
    "                dp[l][r]=max(piles[l]-dp[l+1][r],piles[r]-dp[l][r-1])\n",
    "        print(dp)\n",
    "        return dp[0][n-1]>0\n",
    "        #[l,r]之间的max差值,先手选前，选后"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        n = len(piles)\n",
    "        psum = [[0]*n for _ in range(n)]\n",
    "        for i in range(n):\n",
    "            psum[i][i] = piles[i]\n",
    "        for i in range(n):\n",
    "            for j in range(i+1,n):\n",
    "                psum[i][j] = psum[i][j-1] + piles[j]\n",
    "\n",
    "        dp = [[0]*n for _ in range(n)]\n",
    "        for i in range(n):\n",
    "            dp[i][i] = piles[i]\n",
    "        for i in range(n):\n",
    "            for j in range(i+1,n):\n",
    "                dp[i][j] = max(piles[i]+psum[i][j]-dp[i+1][j],\\\n",
    "                               piles[j]+psum[i][j]-dp[i][j-1])\n",
    "        \n",
    "        return dp[0][n-1]>psum[0][n-1]-dp[0][n-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        n = len(piles)\n",
    "        # dp[i][j] means for piles[i:j] the best you can get\n",
    "        # dp[i][j][0] is the starting first\n",
    "        dp = [[(0,0)] * n for _ in range(n)]\n",
    "        for i in range(n):\n",
    "            dp[i][i] = (piles[i], 0)\n",
    "        # traver from back, because dp[i][j] depends on dp[i + 1][j] and dp[i][j - 1] (down and right)\n",
    "        for i in range(n, -1, -1):\n",
    "            for j in range(i + 1, n):\n",
    "                # pick left or pick right\n",
    "                left = dp[i + 1][j][1] + piles[i]\n",
    "                right = dp[i][j - 1][1] + piles[j]\n",
    "                # first will pick bigger one between left and right\n",
    "                # second will pick whatever is left\n",
    "                if left >= right:\n",
    "                    first = left\n",
    "                    # second have to pick between i + 1 and j\n",
    "                    # this is the same as first for piles[i + 1, j]\n",
    "                    # since we traver from right to left\n",
    "                    second = dp[i + 1][j][0]\n",
    "\n",
    "                else:\n",
    "                    first = right\n",
    "                    second = dp[i][j - 1][0]\n",
    "                dp[i][j] = (first, second)\n",
    "\n",
    "        return dp[0][-1][0] > dp[0][-1][1]\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, nums: List[int]) -> bool:\n",
    "        dp=[[(0,0) for i in range(len(nums))] for j in range(len(nums))]\n",
    "        for i in range(len(nums)):\n",
    "            dp[i][i]=(nums[i], 0)\n",
    "        for i in range(len(nums)-1, -1, -1):\n",
    "            for j in range(i+1, len(nums)):\n",
    "                left=nums[i]+dp[i+1][j][1]\n",
    "                right=nums[j]+dp[i][j-1][1]\n",
    "                if left>right:\n",
    "                    dp[i][j]=(left, dp[i+1][j][0])\n",
    "                else:\n",
    "                    dp[i][j]=(right, dp[i][j-1][0])\n",
    "        return dp[0][-1][0]-dp[0][-1][1]>=0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    dic = {}\n",
    "    def __init__(self): \n",
    "        self.dic = {}\n",
    "    def judge(self,piles,start,end):\n",
    "        #print(self.dic)\n",
    "        if len(piles) > 2:\n",
    "            # A拿前\n",
    "            if str(start+1)+\"+\"+str(end-1) in self.dic:\n",
    "                a1,b1 = self.dic[str(start+1)+\"+\"+str(end-1)]\n",
    "            else:\n",
    "                a1,b1 = self.judge(piles[1:-1],start+1,end-1)\n",
    "            a1 += piles[0]\n",
    "            b1 += piles[-1]\n",
    "            #print('11',a1,b1)\n",
    "            if (str(start+2)+\"+\"+str(end)) in self.dic:\n",
    "                a2,b2 = self.dic[str(start+2)+\"+\"+str(end)]\n",
    "            else:\n",
    "                a2,b2 = self.judge(piles[2:],start+2,end)\n",
    "            a2 += piles[0]\n",
    "            b2 += piles[1]\n",
    "            cha1 = a1 - b1\n",
    "            cha2 = a2 - b2\n",
    "            #print('12',a2,b2)\n",
    "            #print(a1,b1,a2,b2)\n",
    "            if cha1 < cha2:\n",
    "                k = a1,b1\n",
    "            else:\n",
    "                k = a2,b2\n",
    "            #print(k)\n",
    "            # A拿后\n",
    "            if (str(start+1)+\"+\"+str(end-1)) in self.dic:\n",
    "                a3,b3 = self.dic[str(start+1)+\"+\"+str(end-1)]\n",
    "            else:\n",
    "                a3,b3 = self.judge(piles[1:-1],start +1,end -1)\n",
    "            a3 += piles[-1]\n",
    "            b3 += piles[0]\n",
    "            if (str(start)+\"+\"+str(end-2)) in self.dic:\n",
    "                a4,b4 = self.dic[str(start)+\"+\"+str(end-2)]\n",
    "            else:\n",
    "                a4,b4 = self.judge(piles[:-2],start,end -2)\n",
    "            a4 += piles[-1]\n",
    "            b4 += piles[-2]\n",
    "            cha3 = a3 - b3\n",
    "            cha4 = a4 - b4\n",
    "            #print(a3,b3,a4,b4)\n",
    "            if cha3 < cha4:\n",
    "                t = a3,b3\n",
    "            else:\n",
    "                t = a4,b4\n",
    "            #print(t)\n",
    "            if k[0] - k[1] > t[0] - t[1]:\n",
    "                \n",
    "                key = str(start) + '+' + str(end)\n",
    "                self.dic[key] = k\n",
    "                print(key,k)\n",
    "                return k\n",
    "            else:\n",
    "                key = str(start) + '+' + str(end)\n",
    "                self.dic[key] = t\n",
    "                print(key,t)\n",
    "                return t\n",
    "        else:\n",
    "            key = str(start) + '+' + str(end)\n",
    "            self.dic[key] = max(piles),min(piles)\n",
    "            print(key,self.dic[key])\n",
    "            return max(piles),min(piles)\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        res = self.judge(piles,0,len(piles)-1)\n",
    "        if res[0] > res[1]:\n",
    "            return True\n",
    "        else:\n",
    "            return False\n",
    "        return None\n",
    "\n",
    "        \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import numpy as np\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool: \n",
    "        dp=np.zeros((len(piles),len(piles)))\n",
    "\n",
    "        for i in range(len(piles)):\n",
    "            dp[i][i]=piles[i]\n",
    "\n",
    "        for i in range(len(piles)-1):\n",
    "            for j in range(i+1,len(piles)):\n",
    "                dp[i][j] = max(dp[i][i] - dp[i + 1][j], dp[j][j] - dp[i][j - 1])\n",
    "\n",
    "        return int(dp[0][len(piles)-1])>0\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        import numpy as np\n",
    "        n = len(piles)\n",
    "        dp = np.eye(n)\n",
    "        for i in range(n):\n",
    "            dp[i][i] = piles[i]\n",
    "\n",
    "        for i in range(1, n):\n",
    "            for j in range(n - i):\n",
    "                dp[j][j + i] = max(piles[j] - dp[j + 1][j + i], piles[j + i] - dp[j][j + i - 1])\n",
    "\n",
    "\n",
    "        print(dp)\n",
    "        if dp[0][-1] > 0:\n",
    "            return True\n",
    "        return False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        import numpy\n",
    "        dp = numpy.zeros((len(piles), len(piles),2))\n",
    "        n = len(piles)\n",
    "        for index in range(len(piles)):\n",
    "            dp[index][index][0] = piles[index]\n",
    "            dp[index][index][1] = 0\n",
    "        for i in range(n-2, -1, -1):\n",
    "            for j in range(i+1, n):\n",
    "                left = dp[i+1][j][1] + piles[i]\n",
    "                right = dp[i][j-1][1] + piles[j]\n",
    "                if left > right:\n",
    "                    dp[i][j][0] = left\n",
    "                    dp[i][j][1] = dp[i+1][j][0]\n",
    "                else:\n",
    "                    dp[i][j][0] = right\n",
    "                    dp[i][j][1] = dp[i][j-1][0]\n",
    "        return bool(dp[0][n-1][0]-dp[0][n-1][1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        n = len(piles)\n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "        for i in range(n):\n",
    "            dp[i][i] = (piles[i], 0)\n",
    "        for l in range(n-2, -1, -1):\n",
    "            for r in range(l+1, n):\n",
    "                # 先手必胜\n",
    "                if r - l <= 1:\n",
    "                    # dp[l][r] = abs(piles[l] - piles[r])\n",
    "                    dp[l][r] = (max(piles[l],piles[r]), min(piles[l],piles[r]))\n",
    "                else:\n",
    "                    # dp[l][r] = max(dp[l+1][r] + piles[l] - max(dp[l+2][r]+piles[l+1], dp[l+1][r-1]+piles[r]), dp[l][r-1]+piles[r] - max(dp[l+1][r-1]+piles[l], dp[l][r-2]+piles[r]))\n",
    "                    first = max(dp[l+1][r][0] + piles[l], dp[l][r-1][0]+piles[r])\n",
    "                    second = 0\n",
    "                    if first == dp[l+1][r][0] + piles[l]:\n",
    "                        second = max(dp[l+2][r][1]+piles[l+1], dp[l+1][r-1][1]+piles[r])\n",
    "                    else:\n",
    "                        second = max(dp[l+1][r-1][1]+piles[l], dp[l][r-2][1]+piles[r])\n",
    "                    dp[l][r] = (first, second)\n",
    "        print(dp)\n",
    "        return dp[0][n-1][0] > 0\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        n=len(piles)\n",
    "\n",
    "        dp=[[[0,0]for _ in range(n)] for _ in range(n)]\n",
    "\n",
    "        for i in range(n):\n",
    "            dp[i][i][0]=piles[i]\n",
    "            dp[i][i][1]=0\n",
    "\n",
    "        for j in range(n-2,-1,-1):\n",
    "            for k in range(j+1,n):\n",
    "\n",
    "                left=piles[j]+dp[j+1][k][1]\n",
    "                right=piles[j]+dp[j][k-1][1]\n",
    "\n",
    "                if left>right:\n",
    "                    dp[j][k][0]=left\n",
    "                    dp[j][k][1]=dp[j+1][k][1]\n",
    "                else:\n",
    "                    dp[j][k][0]=right\n",
    "                    dp[j][k][1]=dp[j][k-1][1]\n",
    "        \n",
    "        return True if  dp[0][-1][0]-dp[0][-1][1]>=0 else False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        n = len(piles)\n",
    "        # dp[i][j]表示在[i,j]区间内，先手者与后手者各自能够取得的最大石子数量\n",
    "        dp = [[[0]*2 for _ in range(n)] for _ in range(n)]\n",
    "        for i in range(n):\n",
    "            # 区间长度为1时，先手者取得唯一一堆石子，后手者取不到石子\n",
    "            dp[i][i][0],dp[i][i][1] = piles[i], 0\n",
    "        for L in range(2,n+1):\n",
    "            for i in range(0,n-L+1):\n",
    "                l,r = i,i+L-1\n",
    "                # 比较两种情况，先手者先取左边 or 右边，哪一种能够拿到更多石子。\n",
    "                # 先手者取了某一边的石子后，就只能再加上剩余区间的后手石子数量\n",
    "                # 而后手者则是拿到剩余区间的先手石子数量\n",
    "                if piles[l] + dp[l+1][r][1] > piles[r] + dp[l][r-1][1]:\n",
    "                    dp[l][r][0] = piles[l] + dp[l+1][r][1]\n",
    "                    dp[l][r][1] = dp[l+1][r][0]\n",
    "                else:\n",
    "                    dp[l][r][0] = piles[r] + dp[l][r-1][1]\n",
    "                    dp[l][r][1] = dp[l][r-1][0]\n",
    "        # 最后比较完整区间下，先手者取得的最大石子数是否大于后手者即可\n",
    "        return dp[0][n-1][0] > dp[0][n-1][1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        cnt = len(piles)\n",
    "        memo = [[None for i in range(cnt)] for j in range(cnt)]\n",
    "        def dp(i,j):\n",
    "            if memo[i][j]!=None:\n",
    "                return memo[i][j]\n",
    "            #print (i,j)\n",
    "            if i == j:\n",
    "                memo[i][j] = [piles[i], 0]\n",
    "                return memo[i][j]\n",
    "            \n",
    "            if j-i==1:\n",
    "                memo[i][j] = [max(piles[i],piles[j]), min(piles[i], piles[j])]\n",
    "                return memo[i][j] \n",
    "            \n",
    "            if (j-i+1)%2==0: # Bob\n",
    "                a1, b1 = dp(i+1,j)\n",
    "                b1 += piles[i]\n",
    "                a2, b2 = dp(i, j-1)\n",
    "                b2 += piles[j]\n",
    "                if abs(a1-b1) > abs(a2-b2):\n",
    "                    memo[i][j] = [a1,b1]\n",
    "                    return a1,b1\n",
    "                else:\n",
    "                    memo[i][j] = [a2,b2]\n",
    "                    return a2,b2\n",
    "            \n",
    "            else:\n",
    "                a1, b1 = dp(i+1,j)\n",
    "                a1 += piles[i]\n",
    "                a2, b2 = dp(i, j-1)\n",
    "                a2 += piles[j]\n",
    "                if abs(a1-b1) > abs(a2-b2):\n",
    "                    memo[i][j] = [a1,b1]\n",
    "                    return a1,b1\n",
    "                else:\n",
    "                    memo[i][j] = [a2,b2]\n",
    "                    return a2,b2\n",
    "        \n",
    "        \n",
    "        a,b = dp(0, cnt-1)\n",
    "\n",
    "        return a>b\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "            \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        n = len(piles)\n",
    "        memo = [[-float('inf')] * n for _ in range(n)]\n",
    "\n",
    "        def dfs(i: int, j: int):\n",
    "            if i == j:\n",
    "                return piles[i]\n",
    "            if memo[i][j] != -float('inf'):\n",
    "                return memo[i][j]\n",
    "            chooseLeft = piles[i] - dfs(i + 1, j)\n",
    "            chooseRight = piles[j] - dfs(i, j - 1)\n",
    "            res = max(chooseLeft, chooseRight)\n",
    "            memo[i][j] = res\n",
    "            return res\n",
    "\n",
    "        return dfs(0, n - 1) > 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        if len(piles) == 1:\n",
    "            return True\n",
    "        n = len(piles)\n",
    "        dp_table = []\n",
    "        for i in range(n):\n",
    "            sub = [[-1,-1] for i in range(n)]\n",
    "            dp_table.append(sub)\n",
    "        def dp(start, end, is_first):\n",
    "            p = 1 if is_first else 0\n",
    "            if dp_table[start][end][p] != -1:\n",
    "                return dp_table[start][end][p]\n",
    "            \n",
    "            if end - start == 1:\n",
    "                if is_first:\n",
    "                    return max(piles[start], piles[end])\n",
    "                else:\n",
    "                    return min(piles[start], piles[end])\n",
    "            \n",
    "            if is_first:\n",
    "                res = max(\n",
    "                    piles[start] + dp(start+1, end, not is_first),\n",
    "                    piles[end] + dp(start, end-1, not is_first),\n",
    "                )\n",
    "            else:\n",
    "                res = max(\n",
    "                    dp(start+1, end, not is_first),\n",
    "                    dp(start, end-1, not is_first)\n",
    "                )\n",
    "            dp_table[start][end][p] = res\n",
    "            return res\n",
    "        s = sum(piles)\n",
    "        res = dp(0, len(piles)-1, True)\n",
    "        if res > s // 2:\n",
    "            return True\n",
    "        return False\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        dp = dict()\n",
    "        for i in range(len(piles)):\n",
    "            dp[(i, i)] = (piles[i], 0)\n",
    "        for i in range(len(piles)-1, -1, -1):\n",
    "            for j in range(i+1, len(piles)):\n",
    "                first_left = piles[i]+dp[(i+1, j)][1]\n",
    "                first_right = piles[j]+dp[(i, j-1)][1]\n",
    "                if first_left >= first_right:\n",
    "                    first = first_left\n",
    "                    second = dp[(i+1, j)][0]\n",
    "                else:\n",
    "                    first = first_right\n",
    "                    second = dp[(i, j-1)][0]\n",
    "                dp[(i, j)] = (first, second)\n",
    "        first_man = dp[(0, len(piles)-1)][0]\n",
    "        second_man = dp[(0, len(piles)-1)][1]\n",
    "        return first > second_man"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        self.memo = {}\n",
    "        first, right = self.dp(piles, 0, len(piles) - 1)\n",
    "        return first > right\n",
    "\n",
    "    def dp(self, piles, i, j):\n",
    "        if i == j:\n",
    "            return [piles[i], 0]\n",
    "\n",
    "        if (i, j) in self.memo:\n",
    "            return self.memo[(i, j)]\n",
    "            \n",
    "        left, right = piles[i] + self.dp(piles, i + 1, j)[1], piles[j] + self.dp(piles, i, j - 1)[1]\n",
    "\n",
    "        if left > right:\n",
    "            first = left\n",
    "            right = self.dp(piles, i + 1, j)[0]\n",
    "        else:\n",
    "            first = right\n",
    "            right = self.dp(piles, i, j - 1)[0]\n",
    "\n",
    "        self.memo[(i, j)] = [first, right]\n",
    "        return self.memo[(i, j)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        memo = dict()\n",
    "        length = len(piles)\n",
    "        for i in range(length):\n",
    "            memo[i, i] = (piles[i], 0)\n",
    "        for i in range(length, -1, -1):\n",
    "            for j in range(i + 1, length):\n",
    "                # first玩家，取左边第一堆\n",
    "                fir = max((piles[i] + memo[i + 1, j][1]), (piles[j] + memo[i, j - 1][1]))\n",
    "                sec = sum(piles[i:j + 1]) - fir\n",
    "                memo[i, j] = (fir, sec)\n",
    "        return memo[0, length - 1][0] - memo[0, length - 1][1] > 0\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        def dp(i,j,count):\n",
    "            if i == j: return -piles[i]\n",
    "            if memo[i][j][count] != None: return memo[i][j][count]\n",
    "\n",
    "            if count == 0:\n",
    "                res = max(dp(i+1,j, 1)+piles[i], dp(i,j-1, 1)+piles[j])\n",
    "            else:\n",
    "                res = max(dp(i+1,j, 0)-piles[i], dp(i,j-1,0)-piles[j])\n",
    "            memo[i][j][count] = res\n",
    "            \n",
    "            return res \n",
    "\n",
    "        n = len(piles)\n",
    "        memo = [[[None for s in range(2)] for j in range(n)] for i in range(n)]\n",
    "        return True if dp(0,n-1,0) > 0 else False "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        info_dict=dict()\n",
    "        total_sum=sum(piles)\n",
    "        def recur_solution(temp_piles):\n",
    "            key=\"\"\n",
    "            for item in temp_piles:\n",
    "                key+=str(item)\n",
    "            if key in info_dict:\n",
    "                if info_dict[key]*2>total_sum:\n",
    "                    return True,info_dict[key]\n",
    "                return False,info_dict[key]\n",
    "            else:\n",
    "                if len(temp_piles)<=2:\n",
    "                    info_dict[key]=max(temp_piles)\n",
    "                    if info_dict[key]*2>total_sum:\n",
    "                        return True,info_dict[key]\n",
    "                    return False,info_dict[key]\n",
    "                else:\n",
    "                    temp1=temp_piles[:]\n",
    "                    temp2=temp_piles[:]\n",
    "                    temp1.pop(0)\n",
    "                    temp2.pop(-1)\n",
    "                    status,result1=recur_solution(temp1[:])\n",
    "                    if status:\n",
    "                        return status,result1\n",
    "                    elif (result1+temp_piles[0])*2>total_sum:\n",
    "                        return True,result1\n",
    "                    else:\n",
    "                        staus,result2=recur_solution(temp2[:])\n",
    "                        if status:\n",
    "                            return status,result2\n",
    "                        elif (result2+temp_piles[-1])*2>total_sum:\n",
    "                            return True,result2\n",
    "                        else:\n",
    "                            info_dict[key]=max((result1+temp_piles[0],result2+temp_piles[-1]))\n",
    "                            return False,info_dict[key]\n",
    "        status,result=recur_solution(piles[:])\n",
    "        return status\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        n = len(piles)\n",
    "        cache = [[[-1] * 2 for _ in range(n)] for _ in range(n)]\n",
    "        ## True: Alice, False: Bob\n",
    "        def dfs(i, j, flag):\n",
    "            if i > j:\n",
    "                return 0, 0\n",
    "            if cache[i][j][flag] != -1:\n",
    "                return cache[i][j][flag] \n",
    "            if flag:\n",
    "                ## 目的是为了让对方更小\n",
    "                l1, r1 = dfs(i+1, j, not flag)\n",
    "                l2, r2 = dfs(i, j-1, not flag)\n",
    "                res = (l1 + piles[i], r1) if r1 < r2 else (l2 + piles[j], r2)\n",
    "                cache[i][j][flag] = res\n",
    "                return res \n",
    "                \n",
    "            else:\n",
    "                ## 目的是为了让对方更小, 对方哪个小,选哪个\n",
    "                l1, r1 = dfs(i+1, j, not flag)\n",
    "                l2, r2 = dfs(i, j-1, not flag)\n",
    "                res = (l1, r1 + piles[i])  if l1 < l2 else (l2, r2 + piles[j])\n",
    "                cache[i][j][flag] = res\n",
    "                return res\n",
    "        l, r = dfs(0, len(piles) -1, True)\n",
    "        #print(\"l = {}, r = {}\".format(l, r))\n",
    "        return l > r"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        memo = {(i, i):[piles[i], 0] for i in range(len(piles))}\n",
    "        n = len(piles)\n",
    "\n",
    "        def dp(i, j):\n",
    "            if (i, j) in memo:\n",
    "                return memo[(i, j)]\n",
    "\n",
    "            memo[(i, j)] = [0, 0]\n",
    "            # chose left or right\n",
    "            left = piles[i] + dp(i + 1, j)[1]\n",
    "            right = piles[j] + dp(i, j-1)[1]\n",
    "\n",
    "            if left >= right:\n",
    "                memo[(i, j)][0] = left\n",
    "                memo[(i, j)][1] = dp(i + 1, j)[0]\n",
    "            else:\n",
    "                memo[(i, j)][0] = right\n",
    "                memo[(i, j)][1] = dp(i, j-1)[0]\n",
    "            \n",
    "            return memo[(i, j)]\n",
    "\n",
    "        # 为什么这里不用考虑遍历顺序，因为dp结果的定义不同。之前是所有dp结果里面找最优的。所以才需要\n",
    "        \n",
    "        return dp(0, n - 1)[0] - dp(0, n - 1)[1] > 0\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        mem = {}\n",
    "        def dp(i,j):\n",
    "            if i == j:\n",
    "                return piles[i]\n",
    "            if i > j:\n",
    "                return 0 \n",
    "            key = str(i) + ',' + str(j)\n",
    "            if key in mem.keys():\n",
    "                return mem[key] \n",
    "            mem[key] = max(min(dp(i+2,j),dp(i+1,j-1))+piles[i],min(dp(i+1,j-1),dp(i,j-2))+piles[j])\n",
    "            return mem[key] \n",
    "        re = dp(0,len(piles)-1)\n",
    "        # print(re)\n",
    "        return re > sum(piles) // 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class pair:\n",
    "    def __init__(self, first, second):\n",
    "        self.fir = first\n",
    "        self.sec = second\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        n = len(piles)\n",
    "        dp = [[pair(0, 0) for _ in range(n)] for _ in range(n)]\n",
    "\n",
    "        for i in range(n):\n",
    "            dp[i][i].fir = piles[i]\n",
    "            dp[i][i].sec = 0\n",
    "        \n",
    "        for i in range(n - 2, -1, -1):\n",
    "            for j in range(i + 1, n):\n",
    "                left = piles[i] + dp[i + 1][j].sec\n",
    "                right = piles[j] + dp[i][j - 1].sec\n",
    "\n",
    "                if left > right:\n",
    "                    dp[i][j].fir = left\n",
    "                    dp[i][j].sec = dp[i + 1][j].fir\n",
    "                else:\n",
    "                    dp[i][j].fir = right\n",
    "                    dp[i][j].sec = dp[i][j - 1].fir\n",
    "        \n",
    "        res = dp[0][n - 1]\n",
    "\n",
    "        return res.fir - res.sec > 0\n",
    "                    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        n = len(piles)\n",
    "        sums = [[0] * n for _ in range(n)]\n",
    "        for i in range(n - 1, -1, -1):\n",
    "            for j in range(n - 1, i - 1, -1):\n",
    "                if i == j: sums[i][j] = piles[i]\n",
    "                else: sums[i][j] = sums[i + 1][j] + piles[i]\n",
    "        mem = [[0] * n for _ in range(n)]\n",
    "        for i in range(n):\n",
    "            mem[i][i] = piles[i]\n",
    "        \n",
    "        def func(s, e):\n",
    "            if mem[s][e] != 0: return mem[s][e]\n",
    "            mem[s][e] = sums[s][e] - min(func(s + 1, e), func(s, e - 1))\n",
    "            return mem[s][e]\n",
    "        \n",
    "        alice = func(0, n - 1)\n",
    "        bob = sums[0][n - 1] - alice\n",
    "        if alice > bob: return True\n",
    "        else: return False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        s = sum(piles)\n",
    "        @cache\n",
    "        def dfs(i, j):\n",
    "            if j<i: return float('inf')\n",
    "            if i==j:\n",
    "                return piles[i]\n",
    "            return max(piles[i]+min(dfs(i+1,j-1), dfs(i+2,j)), piles[j]+min(dfs(i,j-2),dfs(i+1,j-1)))\n",
    "        return dfs(0, len(piles)-1) > s//2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        def helper(piles, i, j):\n",
    "            if (i, j) in memo:\n",
    "                return memo[(i, j)]\n",
    "\n",
    "            if i == j:\n",
    "                return piles[i]\n",
    "            if i + 1 == j:\n",
    "                return max(piles[i], piles[j])\n",
    "\n",
    "            # 都是聪明人，你如果想要赢实际上就是你在选更大数字的时候，同时要保证留给对方更小的数字\n",
    "            tmp = max(\n",
    "                piles[i] + min(helper(piles, i+1, j-1), helper(piles, i+2, j)),\n",
    "                piles[j] + min(helper(piles, i+1, j-1), helper(piles, i, j-2))\n",
    "                )\n",
    "            memo[(i, j)] = tmp\n",
    "            return tmp\n",
    "\n",
    "        total = sum(piles)\n",
    "        memo = {}\n",
    "        first = helper(piles, 0, len(piles)-1)\n",
    "        return first > (total - first)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        @cache\n",
    "        def dp(start, end):\n",
    "            if start + 1 == end:\n",
    "                return max(piles[start], piles[end])\n",
    "            return max(piles[start] + min(dp(start + 2, end), dp(start + 1, end - 1)), piles[end] + min(dp(start, end - 2), dp(start + 1, end - 1)))\n",
    "        n, total = len(piles), sum(piles)\n",
    "        return dp(0, n - 1) > total - dp(0, n - 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        n=len(piles)\n",
    "        m=sum(piles)\n",
    "        if n==1:\n",
    "            return True\n",
    "        @cache\n",
    "        def dfs(i,j):\n",
    "            if i>j:\n",
    "                return 0\n",
    "            a=dfs(i+2,j)\n",
    "            b=dfs(i+1,j-1)\n",
    "            d=dfs(i,j-2)\n",
    "            return max(a+piles[i],b+piles[i],b+piles[j],d+piles[j])\n",
    "        ans=dfs(0,n-1)\n",
    "        if ans>m-ans:\n",
    "            return True\n",
    "        else :\n",
    "            return False\n",
    "            \n",
    "\n",
    "                "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import numpy as np\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        n = len(piles)\n",
    "        dp = np.zeros((n,n,2)).tolist()\n",
    "        # 初始状态\n",
    "        for i in range(n):\n",
    "            dp[i][i][0] = piles[i]\n",
    "            dp[i][i][1] = 0\n",
    "        for i in range(n-2, -1, -1):\n",
    "            for j in range(i+1, n):\n",
    "                left = piles[i]+dp[i+1][j][1]\n",
    "                right = piles[j]+dp[i][j-1][1]\n",
    "                if left >= right:\n",
    "                    dp[i][j][0] = left\n",
    "                    dp[i][j][1] = dp[i+1][j][0]\n",
    "                else:\n",
    "                    dp[i][j][0] = right\n",
    "                    dp[i][j][1] = dp[i][j-1][0]\n",
    "        return True if dp[0][n-1][0]>dp[0][n-1][1] else False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        N = len(piles)\n",
    "        memo = collections.defaultdict(dict)       \n",
    "\n",
    "        def dp(A, i, j):\n",
    "            if i>j:\n",
    "                return 0\n",
    "\n",
    "            if i in memo and j in memo[i]:\n",
    "                return memo[i][j]\n",
    "\n",
    "            parity = (j-i)%2\n",
    "            if parity==1:\n",
    "                score = max(A[i]+dp(A,i+1,j), A[j]+dp(A,i,j-1))\n",
    "            else:\n",
    "                score = min(-1*A[i]+dp(A,i+1,j), -1*A[j]+dp(A,i,j-1))\n",
    "            memo[i][j] = score\n",
    "            return score\n",
    "\n",
    "        res = dp(piles, 0, N-1)\n",
    "\n",
    "        return res>0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        @cache\n",
    "        def min_max(l, r):\n",
    "            if l > r:\n",
    "                return 0\n",
    "            \n",
    "\n",
    "            if dp[l][r] == 0:\n",
    "                max_l = piles[l] + min(min_max(l+2, r), min_max(l+1, r-1))\n",
    "                max_r = piles[r] + min(min_max(l, r - 2), min_max(l+1, r-1))\n",
    "                dp[l][r] = max(max_l, max_r)\n",
    "            \n",
    "            return dp[l][r]\n",
    "            \n",
    "\n",
    "        dp = [[0]*len(piles) for i in range(len(piles))]\n",
    "        return min_max(0, len(piles) - 1) > 0\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        memo = [[-1]*len(piles) for _ in range(len(piles))]\n",
    "        def dp(i, j):\n",
    "            if i > j: return 0\n",
    "            if i == j:\n",
    "                return (piles[i], 0)\n",
    "            if memo[i][j] != -1:\n",
    "                return memo[i][j]\n",
    "            first = max(piles[i] + dp(i+1, j)[1], piles[j] + dp(i, j-1)[1])\n",
    "            second = min(dp(i+1, j)[0], dp(i, j-1)[0])\n",
    "            memo[i][j] = (first, second)\n",
    "            return memo[i][j]\n",
    "        s = dp(0, len(piles)-1) \n",
    "        return s[0] > s[1]\n",
    "            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\r\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\r\n",
    "        dp_table = []\r\n",
    "        for _ in range(len(piles)):\r\n",
    "            dp_table.append([(-1, -1)] * len(piles))\r\n",
    "        def dp(i, j):\r\n",
    "            if i == j:\r\n",
    "                return piles[i], 0\r\n",
    "            \r\n",
    "            if dp_table[i][j][0] != -1 and dp_table[i][j][1] != -1:\r\n",
    "                return dp_table[i][j]\r\n",
    "\r\n",
    "            left_s, left_f  = dp(i+1, j)\r\n",
    "            right_s, right_f = dp(i, j-1)\r\n",
    "            left = left_f + piles[i]\r\n",
    "            right = right_f + piles[j]\r\n",
    "            if left > right:\r\n",
    "                dp_table[i][j] = (left, left_s)\r\n",
    "                return left, left_s\r\n",
    "            else:\r\n",
    "                dp_table[i][j] = (right, right_s)\r\n",
    "                return right, right_s\r\n",
    "\r\n",
    "        A, B = dp(0, len(piles)-1)\r\n",
    "        print(A, B)\r\n",
    "        return A > B"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        dp = []\n",
    "        # init\n",
    "        for i in range(len(piles)):\n",
    "            dp.append([(0,0)]*i + [(piles[i], 0)] + [(0,0)] * (len(piles)-i-1))\n",
    "        \n",
    "        def search(i,j):\n",
    "            if dp[i][j][0] != 0 or dp[i][j][1] != 0:\n",
    "                return dp[i][j]\n",
    "            ans = None\n",
    "            left = search(i, j-1)\n",
    "            right = search(i+1, j)\n",
    "            if left[1] + piles[j] > right[1] + piles[i]:\n",
    "                ans = (left[1] + piles[j], left[0])\n",
    "            else:\n",
    "                ans = (right[1] + piles[i], right[0])\n",
    "            dp[i][j] = ans\n",
    "            return ans\n",
    "\n",
    "        first, second = search(0, len(piles)-1)\n",
    "        return first > second"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        dp = []\n",
    "        for i in range(len(piles)):\n",
    "            dp.append([])\n",
    "            for j in range(len(piles)):\n",
    "                dp[i].append([[0, 0], [0, 0]])\n",
    "\n",
    "        for i in range(1, len(piles) + 1):\n",
    "            for j in range(len(piles) - i + 1):\n",
    "                L = j\n",
    "                R = j + i - 1\n",
    "                if L == R:\n",
    "                    dp[L][R][0][0] = piles[L]\n",
    "                    dp[L][R][0][1] = 0\n",
    "                    dp[L][R][1][0] = 0\n",
    "                    dp[L][R][1][1] = piles[L]\n",
    "                else:\n",
    "                    dp[L][R][0][0] = max(piles[L] + dp[L + 1][R][1][0], piles[R] + dp[L][R - 1][1][0])\n",
    "                    dp[L][R][0][1] = min(dp[L + 1][R][1][1], dp[L][R - 1][1][1])\n",
    "                    dp[L][R][1][0] = min(dp[L + 1][R][0][0], dp[L][R - 1][0][0])\n",
    "                    dp[L][R][1][1] = max(piles[L] + dp[L + 1][R][0][1], piles[R] + dp[L][R - 1][0][1])\n",
    "        \n",
    "        return dp[0][len(piles) - 1][0][0] >= dp[0][len(piles) - 1][0][1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        # 自己思考\n",
    "        # 收到第245场周赛最后一题y总的影响，这题本来是递归的，即假如A取了第一个，那么接下来就是 helper(nums[1:],B)，否则就是 helper(nums[:-1],B)，但看了y总的思路，这其实是可以把递归变成矩阵dp，设dp[i][j][0]为nums[i...j]中A先取则A可以得到的最大分数(B行为最优的情况下)和B会得到的分数，dp[i][j][1]为nums[i..j]中B先取的话可以得到的分数，从右下往左上遍历即可。\n",
    "        dp = [ [ [[0,0],[0,0]] for _ in range(len(piles))] for _ in range(len(piles))]\n",
    "        for i in range(len(piles)-1,-1,-1):\n",
    "            for j in range(i,len(piles)):\n",
    "                if i==j:\n",
    "                    dp[i][j] = [[piles[i],0],[0,piles[i]]]\n",
    "                else:\n",
    "                    dp[i][j][0][0] = max(dp[i+1][j][1][0]+piles[i], dp[i][j-1][1][0]+piles[j])\n",
    "                    dp[i][j][0][1] = min(dp[i+1][j][1][1], dp[i][j-1][1][1])\n",
    "                    dp[i][j][1][1] = max(dp[i+1][j][0][1]+piles[i], dp[i][j-1][0][1]+piles[j])\n",
    "                    dp[i][j][1][0] = min(dp[i+1][j][0][0], dp[i][j-1][0][0])\n",
    "        # for i in range(len(piles)):\n",
    "        #     print(dp[i])\n",
    "        return dp[0][-1][0][0]>=dp[0][-1][0][1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "\n",
    "        rocks = piles\n",
    "\n",
    "        @lru_cache(maxsize=250000)\n",
    "        def win(l, r):    \n",
    "            if r - l == 2:\n",
    "                return max(rocks[l:r])\n",
    "            \n",
    "            x = win(l+2, r)\n",
    "            y = win(l+1, r-1)\n",
    "            z = win(l, r-2)\n",
    "            return max(rocks[l] + min(x, y),  min(y, z)+rocks[r-1])\n",
    "\n",
    "        return True if win(0, len(rocks)) > sum(piles) // 2 else False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        @cache\n",
    "        def dfs(start, end, alice):\n",
    "            if start == end:\n",
    "                if alice:\n",
    "                    return [piles[start], 0]\n",
    "                else:\n",
    "                    return [0, piles[start]]\n",
    "            if alice:\n",
    "                temp1 = dfs(start + 1, end, False)\n",
    "                temp1[0] += piles[start]\n",
    "                temp2 = dfs(start, end - 1, False)\n",
    "                temp2[0] += piles[end]\n",
    "                return temp1 if temp1[0] >= temp2[0] else temp2\n",
    "            else:\n",
    "                temp1 = dfs(start + 1, end, True)\n",
    "                temp1[1] += piles[start]\n",
    "                temp2 = dfs(start, end - 1, True)\n",
    "                temp2[1] += piles[end]\n",
    "                return temp1 if temp1[1] >= temp2[1] else temp2\n",
    "\n",
    "        return dfs(0, len(piles) - 1, True)[0] > sum(piles) // 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        def max1(pile,i,j,record={}):\n",
    "            if i == j:\n",
    "                return 0\n",
    "            if f'{i}_{j}' in record:\n",
    "                return record[f'{i}_{j}']\n",
    "            if (j-i+1)%2==0:\n",
    "                 maxret1 = max1(pile,i+1,j,record)+pile[i]\n",
    "                 maxret2 = max1(pile,i,j-1,record)+pile[j]\n",
    "                 if maxret1 > maxret2:\n",
    "                     record[f'{i}_{j}'] = maxret1\n",
    "                     return maxret1\n",
    "                 else:\n",
    "                    record[f'{i}_{j}'] = maxret2\n",
    "                    return maxret2\n",
    "                 \n",
    "            else:\n",
    "                maxret1 = max1(pile,i+1,j,record)\n",
    "                maxret2 = max1(pile,i,j-1,record)\n",
    "                if maxret1 > maxret2:\n",
    "                     record[f'{i}_{j}'] = maxret1\n",
    "                     return maxret1\n",
    "                else:\n",
    "                    record[f'{i}_{j}'] = maxret2\n",
    "                    return maxret2\n",
    "                return max(max1(pile,i+1,j,record) ,max1(pile,i,j-1,record))\n",
    "            \n",
    "        player1 = max1(piles,0,len(piles)-1)\n",
    "        player2 = sum(piles)-player1\n",
    "        return player1>player2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        n = len(piles)\n",
    "        dic = {}\n",
    "        def dfslr(l, r):\n",
    "            # print(l, r)\n",
    "            if l > r:\n",
    "                return (0, 0)\n",
    "            elif (l,r) not in dic:\n",
    "                llmaa, llmab = dfslr(l+2, r)\n",
    "                lrmaa, lrmab = dfslr(l+1, r-1)\n",
    "                rrmaa, rrmab = dfslr(l, r-2)\n",
    "                if min(llmaa, lrmaa)+piles[l] > min(rrmaa, lrmaa)+piles[r]:\n",
    "                    dic[(l,r)] = (min(llmaa, lrmaa)+piles[l], max(llmab+piles[l+1], piles[r]+lrmab))\n",
    "                else:\n",
    "                    dic[(l,r)] = (min(rrmaa, lrmaa)+piles[r], max(rrmab+piles[r-1], piles[l]+lrmab))\n",
    "            res = dic[(l,r)]\n",
    "            return res\n",
    "        a, b = dfslr(0, n-1)\n",
    "        # print(a,b)\n",
    "        return a > b\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        @cache\n",
    "        def recurse(i, j):\n",
    "            if i==j:\n",
    "                return piles[i]\n",
    "            l = piles[i] - recurse(i+1, j)\n",
    "            r = piles[j] - recurse(i,j-1)\n",
    "            return l if l> j else j\n",
    "        return recurse(0, len(piles)-1) > 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    # dp[0][i][j]=max dp[1][i][j-1]+piles[j],dp[1][i+1][j]+piles[i]\n",
    "    # dp[1][i][j]=min dp[0][i][j-1],dp[0][i+1][j]\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        mem={}\n",
    "        def sol(k,i,j):\n",
    "            \n",
    "            if (k,i,j) in mem:\n",
    "                return mem[(k,i,j)]\n",
    "            if k==0:\n",
    "                if i==j:\n",
    "                    ans=piles[i]\n",
    "                else:\n",
    "                    ans=max(sol(1,i,j-1)+piles[j],sol(1,i+1,j)+piles[i])\n",
    "            else:\n",
    "                if i==j:\n",
    "                    ans=0\n",
    "                else:\n",
    "                    ans=min(sol(0,i,j-1),sol(0,i+1,j))\n",
    "            mem[(k,i,j)]=ans\n",
    "            return ans \n",
    "        ans=sol(0,0,len(piles)-1)\n",
    "        s=sum(piles)\n",
    "        return ans>s/2\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        dp = defaultdict(int)\n",
    "\n",
    "        def dfs(i,j):\n",
    "            if i == j:\n",
    "                return piles[i]\n",
    "            if dp[(i,j)]:\n",
    "                return dp[(i,j)]\n",
    "            \n",
    "            dp[(i,j)] = max(piles[i] - dfs(i+1,j), piles[i] - dfs(i,j-1))\n",
    "            return dp[(i,j)]\n",
    "        dfs(0,len(piles)-1)\n",
    "        return True if dp[(0,len(piles)-1)] >=0 else False\n",
    "        \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "\n",
    "        @cache\n",
    "        def f(l,r):\n",
    "            if abs(l-r) == 1:\n",
    "                return max(piles[l],piles[r])\n",
    "            \n",
    "            return max(piles[l] + g(l+1,r),piles[r] + g(l,r-1))\n",
    "\n",
    "        @cache      \n",
    "        def g(l,r):\n",
    "            if abs(l-r) == 1:\n",
    "                return 0\n",
    "            return min(f(l+1,r),f(l,r-1))\n",
    "\n",
    "        if sum(piles) - f(0,len(piles)-1) > f(0,len(piles)-1):\n",
    "            return False\n",
    "\n",
    "        else:\n",
    "            return True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "\n",
    "        @cache\n",
    "        def f(l,r):\n",
    "            if abs(l-r) == 1:\n",
    "\n",
    "                return max(piles[l],piles[r])\n",
    "            \n",
    "            return max(piles[l] + g(l+1,r),piles[r] + g(l,r-1))\n",
    "\n",
    "        @cache      \n",
    "        def g(l,r):\n",
    " \n",
    "            return min(f(l+1,r),f(l,r-1))\n",
    "\n",
    "        if sum(piles) - f(0,len(piles)-1) > f(0,len(piles)-1):\n",
    "            return False\n",
    "\n",
    "        else:\n",
    "            return True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        SCORE = {(i,i):0 for i in range(len(piles)+1)}\n",
    "        def score(i,j):\n",
    "            if (i,j) in SCORE:\n",
    "                return SCORE[i,j]\n",
    "            if (j-i) % 2:\n",
    "                a = score(i,j-1) - piles[j-1]\n",
    "                b = score(i+1,j) - piles[i]\n",
    "                SCORE[i,j] = min(a,b)\n",
    "            else:\n",
    "                a = score(i,j-1) + piles[j-1]\n",
    "                print(\"a\",score(i,j-1), piles[j-1])\n",
    "                b = score(i+1,j) + piles[i]\n",
    "                print(\"b\",score(i+1,j), piles[i])\n",
    "                print(i,j)\n",
    "                SCORE[i,j] = max(a,b)\n",
    "            return SCORE[i,j]\n",
    "        i,j = 0,len(piles)\n",
    "        print(SCORE)\n",
    "        return score(i,j) > 0\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from functools import cache\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        n = len(piles)\n",
    "        # s = [piles[-1]]\n",
    "        # for i in range(n-2, -1, -1):\n",
    "        #     s = [s[0]+piles[i]] + s\n",
    "        # dfs: max stone that current player can take, starting from idx i with current m\n",
    "        # layer number for turn sequencial\n",
    "        @cache\n",
    "        def dfs(i, llen):\n",
    "            if llen == 2:\n",
    "            # if i+2*m>=n-1: # i=0, m=1, n=2\n",
    "                return piles[i] if  piles[i] > piles[i+1] else piles[i+1]\n",
    "            return max(piles[i] - dfs(i+1, llen-1), piles[i+llen-1] - dfs(i, llen-1))\n",
    "        return dfs(0,n) > 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        n = len(piles)\n",
    "        s = len(piles)\n",
    "        @cache\n",
    "        def dfs(i, j, a_or_b):  # piles[i: j + 1] 哪个先走，返回Alice拿到的石头数\n",
    "            if i > j: return 0\n",
    "            if a_or_b:\n",
    "                return max(dfs(i + 1, j, not a_or_b) + piles[i], dfs(i, j - 1, not a_or_b) + piles[j])\n",
    "            return max(dfs(i + 1, j, not a_or_b), dfs(i, j - 1, not a_or_b))\n",
    "        s1 = dfs(0, n - 1, True)\n",
    "        return s1 * 2 > s"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        n = len(piles)\n",
    "        half_sum = sum(piles) / 2\n",
    "\n",
    "        @cache\n",
    "        def dfs(l, r):\n",
    "            \"\"\"当前先手的人能拿到的最多石子数\"\"\"\n",
    "            if l == r:\n",
    "                return piles[l]\n",
    "            maxl = dfs(l + 1, r)\n",
    "            maxr = dfs(l, r - 1)\n",
    "            if maxl is True or maxr is True:\n",
    "                return True\n",
    "\n",
    "            result = max(piles[l] + maxl, piles[r] + maxr)\n",
    "            if result > half_sum:\n",
    "                return True\n",
    "            return result\n",
    "\n",
    "        alice = dfs(0, n-1)\n",
    "        bob = sum(piles) - alice\n",
    "\n",
    "        return alice is True or alice > bob"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        @cache\n",
    "        def dfs(l, r, sign):\n",
    "            if l > r:\n",
    "                return 0\n",
    "            left = piles[l] if sign else 0\n",
    "            right = piles[r] if sign else 0\n",
    "            if sign:\n",
    "                res = max(dfs(l + 1, r, not sign) + left, dfs(l, r - 1, not sign) + right)\n",
    "            else:\n",
    "                res = min(dfs(l + 1, r, not sign) + left, dfs(l, r - 1, not sign))\n",
    "            return res\n",
    "        return dfs(0, len(piles) - 1, True) > sum(piles) / 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, piles: List[int]) -> bool:\n",
    "        @cache\n",
    "        def dfs(l, r, sign):\n",
    "            if l > r:\n",
    "                return 0\n",
    "            left = piles[l] if sign else 0\n",
    "            right = piles[r] if sign else 0\n",
    "            if sign:\n",
    "                res = max(dfs(l + 1, r, not sign) + left, dfs(l, r - 1, not sign) + right)\n",
    "            else:\n",
    "                res = min(dfs(l + 1, r, not sign) + left, dfs(l, r - 1, not sign))\n",
    "            return res\n",
    "        return dfs(0, len(piles) - 1, True) > sum(piles) / 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def stoneGame(self, nums: List[int]) -> bool:\n",
    "        n=len(nums)\n",
    "        @cache\n",
    "        def f(i,j,turn):\n",
    "            if i==j:\n",
    "                return nums[i]\n",
    "            res1= nums[i] - f(i+1,j,-turn)\n",
    "            res2= nums[j] - f(i,j-1,-turn)\n",
    "            return max(res1,res2)\n",
    "        return f(0,n-1,1)>=0"
   ]
  }
 ],
 "metadata": {},
 "nbformat": 4,
 "nbformat_minor": 2
}
